微信小程序的使用能夠快速的基於場景進行用戶圈的創建推廣,其中根據業務須要使用用戶信息以及受權過程,主要用到的有微信在開發工具中已經封裝好的 api 函數:wx.login、wx.getUserInfo、wx.checkSession、wx.getStorageSync、wx.request等php
參數 類型 說明 userInfo OBJECT 用戶信息對象,不包含 openid 等敏感信息 rawData String 不包括敏感信息的原始數據字符串,用於計算簽名。 signature String 使用 sha1( rawData + sessionkey ) 獲得字符串,用於校驗用戶信息,參考文檔 signature。 encryptedData String 包括敏感數據在內的完整用戶信息的加密數據,詳細見加密數據解密算法 iv String 加密算法的初始向量,詳細見加密數據解密算法
//調用成功後返回結果示例 { encryptedData:"6exNeBvACX+EpzLNF2vYRhM0Z1tNZnBOYP0Qh6jQ4Ofv+69qY/RGVAB34aj4f364mkjAAD5pgDDJ41hGkkr/IaHJGioI3EhGSEQyrAfE1mPovV9s6Prg4rKedfBUerG4jEgXbS0GeERMtJ15tqEGz7qzcA49c1D1obZTuneImZq1vB1lXo3oUbnmK7LUAxQcgCQA==", errMsg:"getUserInfo:ok", iv:"X6PuFoueBpfgyjV9l9D6A==", rawData:"{"nickName":"xxx","gender":1,"language":"zh_CN","city":"","province":"","country":"Iceland","avatarUrl":"https://wx.qlogo.cn/mmsen/vi_s/0daYVYsscPNxEvALzBTsJarXwUmlxjZJZMHPM6NNLegH4wLRcRlsA1x4bsJg/132"}", signature:"c32wba325164258b9a332b6fdsdew2e520081348", userInfo: { avatarUrl:"https://wx.qlogo.cn/mmsen/vi_s/0daYVYsscPNxEvALzBTsJarXwUmlxjZJZMHPM6NNLegH4wLRcRlsA1x4bsJg/132", city:"", country:"Iceland", gender:1, language:"zh_CN", nickName:"xxx", province:"" } }
{ "openId": "OPENID", "nickName": "NICKNAME", "gender": GENDER, "city": "CITY", "province": "PROVINCE", "country": "COUNTRY", "avatarUrl": "AVATARURL", "unionId": "UNIONID", "watermark": //數據水印 { "appid":"APPID", //敏感數據歸屬appid,開發者可校驗此參數與自身appid是否一致 "timestamp":TIMESTAMP //敏感數據獲取的時間戳, 開發者能夠用於數據時效性校驗 } }
官方給的圖示:(大概步驟能夠看官方文檔)
基本:其中使用wx.login()能夠得到開發者服務器向微信接口服務器請求得到session_key等數據時所須要的參數code,開發者服務器以code+appid+app secret(小程序祕鑰,管理後臺能夠得到)換取 用戶惟一標識openid 和 會話密鑰session_key。但每一次調用wx.login()都會更新微信接口服務器上的session_key。html
首次登陸node
獲取登陸憑證code——>發送至開發者服務器構造接口( appid + app secret + code) 請求 微信接口服務器數據——>返回用戶數據密鑰session_key 和惟一標識openid給開發者服務器——>根據session_key 和 openid等生成自定義的第三方session,存儲session_key至開發者服務器,不能將session_key發送至客戶端,防止敏感數據泄露——>將第三方自定義登陸信息session發送至客戶端——>保存自定義第三方登陸態信息session到本地緩存,登陸成功,能夠設置一個登陸標識flag,使flag=true表示首次登陸成功,進行相關的處理操做。
其中,登陸校驗憑證接口(在開發者服務器中調用,小程序中沒法使用此接口)爲:c++
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code appid 小程序惟一標識 secret 小程序的 app secret js_code 是wx.login登陸時獲取的憑證code grant_type 填寫爲 authorization_code
具體僞代碼以下:算法
/** * 我把這一步封裝成一個函數,之後再調用那些須要登陸後纔有權限訪問的後臺服務時. * 可使用使用這個函數操做,基本邏輯,還能夠進行擴展 * @url : 開發者服務器登陸服務接口 可設置默認值 * @key : 存入本地緩存的第三方自定義登陸session的鍵值 * @callback : 須要用到登陸服務的回調函數(或函數集合) */ function Login(key,url,callback){ // 首先使用wx.login獲取登陸憑證code併發送給開發者服務器 wx.login({ success: function(res) { if (res.code) { //發送code給開發者服務器以獲取session_key和openid wx.request({ url:url, data: { code: res.code }, //發送至開發者服務器成功 success: function(res) { //開發者服務器得到session_key和openid成功並返回了 //第三方自定義session或者解密數據等json格式數據res給客戶端 if(res.has3rdSession){ //登陸成功,將第三方session存入本地緩存 console.log("登陸成功") wx.setStorageSync(key,res.3rdSession) //設置登陸標識爲true this.setData{ flag:true } //進行後續回調處理 callback(res) .... } else{ //沒有返回第三方自定義session,登陸失敗 console.log("登陸失敗") .... } } }) } else { //沒有獲取到登陸憑證code,登陸失敗 console.log('登陸失敗!' + res.errMsg) .... } } }) }
wx.getStorageSync()查詢本地緩存中是否有咱們自定義的session登陸態信息,有的話證實不是第一次登陸,此時先查詢微信接口服務器上的用戶session_key是否過時,若是過時了,無論咱們本身定義的session如何,都要從新登陸,設置登陸標識flag爲false;若是沒有過時,那麼能夠向開發者服務器發送sessio查詢用戶信息,若是開發者服務器告訴咱們本身定義的session過時了,那從新登陸,設置登陸標識flag爲false,若是沒有過時,則查詢是否有這個session來得到用戶的相關信息,具體僞代碼以下:json
/** - 我把這一步封裝成一個函數,之後再調用那些須要登陸後纔有權限訪問的後臺服務時. - 可使用使用這個函數操做,基本邏輯,還能夠進行擴展 - @url : 開發者服務器服務接口 - @key : 本身定義的session存儲在本地緩存中的鍵名 - @callback : 須要用到登陸服務的回調函數(或函數集合) - @others : 其餘須要用到的數據等參數 */ function doRequestWithSession(key,url,callback,others) { try { var value = wx.getStorageSync(key) if (value) { // 存在自定義登陸session,非首次登陸 // 查詢 用戶密鑰session_key是否過時 wx.checkSession({ success: function(){ //session_key 未過時,而且在本生命週期一直有效 //向開發者服務器發送自定義session查詢用戶信息 wx.request({ url: url, data: value, //本地緩存的自定義Session值 能夠加上其餘須要的數據others等 success: function(res) { if(res.hasSession){ //查詢成功,開發者服務器上有咱們自定義的session //根據返回結果進行對應的操做,先判斷session是否過時 //若是咱們自定義的session已通過期 if(res.expired){ console.log("session過時,從新登陸") //設置登陸標識爲false this.setData{ flag:false } wx.login() //從新登陸 或者 返回錯誤碼 .... } else{ //沒有過時,返回的結果則能夠是用戶的相關信息 //進行相關操做 登陸成功 console.log("歡迎回來") callback(res) .... } } else { //開發者服務器上沒有咱們自定義的session,從新登陸 console.log("無此session,從新登陸") //設置登陸標識爲false this.setData{ flag:false } wx.login() //從新登陸 或者 返回錯誤碼 .... } } }) }, fail: function(){ // session_key 已經失效,須要從新執行登陸流程 //設置登陸標識爲false this.setData{ flag:false } wx.login() //從新登陸 或者 返回錯誤碼 .... } }) } else{ //本地緩存中沒有自定義的session登陸態信息,則進行首次登陸或者後續處理 //設置登陸標識爲false this.setData{ flag:false } wx.login() //登陸 或者 返回錯誤碼 .... } } catch (e) { // 異常處理 .... } }
if(this.data.flag){ //已經登陸過,非首次登陸 doRequestWithSession(key,url,callback,others) .... } else{ //沒有登陸過,能夠進一步檢查本地緩存是否有3rdSession do other things .... }
在第一部分已經說過敏感數據和開放數據,能夠用 wx.getUserInfo得到開放數據,可是沒有登陸獲取解密密鑰session_key是沒法解密敏感數據的,因此開放數據中,沒有登陸的話,咱們只能得到用戶暱稱、頭像、城市、性別、國籍等,並無能夠標識用戶的惟一id。因此如何拿到咱們的安全的原始數據,只有:獲取開放數據——>得到登陸權限,開發者服務器得到密鑰session_key校驗簽名解密數據——>返回解密數據,包含有openid。僞代碼:小程序
a.wxml 文件:微信小程序
//wx.getUserInfo接口有調整,使用該接口將再也不出現受權彈窗,要使用 <button>組件引導用戶主動進行受權操做,使用此接口要注意: //當用戶未受權過,調用該接口將直接報錯;當用戶受權過,可使用該接口獲取用戶信息 //例子 <button open-type='getUserInfo' bindgetuserinfo='showUserInfo'>登陸</button>
a.js 文件:api
Page({ data:{}, ... //點擊登陸按鈕後觸發 showUserInfo:function(e){ //獲取須要解密的數據 var encryptedData = e.detail.encryptedData /* *@key 第三方自定義登陸session存在本地緩存的key值 *@url 解密敏感數據的開發者服務器服務接口 *@callback 得到解密數據後的回調函數 *@encryptedData 當前得到的未解密數據 */ doRequestWithSession(key,url,callback,encryptedData) }, })
後臺的服務有不少,能夠作API平臺進行統一管理:緩存
其中的解密代碼示例 (官方4種語言版本:Python、php、c++、node):
<?php class WXBizDataCrypt { private $appid; private $sessionKey; /** * 構造函數 * @param $sessionKey string 用戶在小程序登陸後獲取的會話密鑰 * @param $appid string 小程序的appid */ public function __construct( $appid, $sessionKey) { $this->sessionKey = $sessionKey; $this->appid = $appid; } /** * 檢驗數據的真實性,而且獲取解密後的明文. * @param $encryptedData string 加密的用戶數據 * @param $iv string 與用戶數據一同返回的初始向量 * @param $data string 解密後的原文 * * @return int 成功0,失敗返回對應的錯誤碼 */ public function decryptData( $encryptedData, $iv, &$data ) { if (strlen($this->sessionKey) != 24) { return ErrorCode::$IllegalAesKey; } $aesKey=base64_decode($this->sessionKey); if (strlen($iv) != 24) { return ErrorCode::$IllegalIv; } $aesIV=base64_decode($iv); $aesCipher=base64_decode($encryptedData); $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV); $dataObj=json_decode( $result ); if( $dataObj == NULL ) { return ErrorCode::$IllegalBuffer; } if( $dataObj->watermark->appid != $this->appid ) { return ErrorCode::$IllegalBuffer; } $data = $result; return ErrorCode::$OK; } } $appid = 'wx4f4bc4dec97d474b'; $sessionKey = 'tiihtNczf5v6AKRyjwEUhQ=='; $encryptedData="CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZM QmRzooG2xrDcvSnxIMXFufNstNGTyaGS 9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+ 3hVbJSRgv+4lGOETKUQz6OYStslQ142d NCuabNPGBzlooOmB231qMM85d2/fV6Ch evvXvQP8Hkue1poOFtnEtpyxVLW1zAo6 /1Xx1COxFvrc2d7UL/lmHInNlxuacJXw u0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn /Hz7saL8xz+W//FRAUid1OksQaQx4CMs 8LOddcQhULW4ucetDf96JcR3g0gfRK4P C7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB 6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns /8wR2SiRS7MNACwTyrGvt9ts8p12PKFd lqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYV oKlaRv85IfVunYzO0IKXsyl7JCUjCpoG 20f0a04COwfneQAGGwd5oa+T8yO5hzuy Db/XcxxmK01EpqOyuxINew=="; $iv = 'r7BXXKkLb8qrSNn05n0qiA=='; $pc = new WXBizDataCrypt($appid, $sessionKey); $errCode = $pc->decryptData($encryptedData, $iv, $data ); if ($errCode == 0) { print($data . "\n"); } else { print($errCode . "\n"); } ?>
接觸不深 ,權當記錄。錯漏處還望多多指正~
參考閱讀: