背景微信小程序的使用可以快速的基于場(chǎng)景進(jìn)行用戶圈的建立推廣,其中根據(jù)業(yè)務(wù)需要使用用戶信息以及授權(quán)過程,主要用到的有微信在開發(fā)工具中已經(jīng)封裝好的 api 函數(shù):wx.login、wx.getUserInfo、wx.checkSession、wx.getStorageSync、wx.request等 1. 關(guān)鍵詞
參數(shù) 類型 說明 userInfo OBJECT 用戶信息對(duì)象,不包含 openid 等敏感信息 rawData String 不包括敏感信息的原始數(shù)據(jù)字符串,用于計(jì)算簽名。 signature String 使用 sha1( rawData + sessionkey ) 得到字符串,用于校驗(yàn)用戶信息,參考文檔 signature。 encryptedData String 包括敏感數(shù)據(jù)在內(nèi)的完整用戶信息的加密數(shù)據(jù),詳細(xì)見加密數(shù)據(jù)解密算法 iv String 加密算法的初始向量,詳細(xì)見加密數(shù)據(jù)解密算法 //調(diào)用成功后返回結(jié)果示例 { encryptedData:"6exNeBvACX+EpzLNF2vYRhM0Z1tNZnBOYP0Qh6jQ4Ofv+69qY/RGVAB34aj4f364mkjAAD5pgDDJ41hGkkr/IaHJGioI3EhGSEQyrAfE1mPovV9s6Prg4rKedfBUerG4jEgXbS0GeERMtJ15tqEGz7qzcA49c1D1obZTuneImZq1vB1lXo3oUbnm*LUAxQcgCQA==", 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": //數(shù)據(jù)水印 { "appid":"APPID", //敏感數(shù)據(jù)歸屬appid,開發(fā)者可校驗(yàn)此參數(shù)與自身appid是否一致 "timestamp":TIMESTAMP //敏感數(shù)據(jù)獲取的時(shí)間戳, 開發(fā)者可以用于數(shù)據(jù)時(shí)效性校驗(yàn) } }
2.登錄官方給的圖示:(大概步驟可以看官方文檔)
基本:其中使用wx.login()可以獲得開發(fā)者服務(wù)器向微信接口服務(wù)器請(qǐng)求獲得session_key等數(shù)據(jù)時(shí)所需要的參數(shù)code,開發(fā)者服務(wù)器以code+appid+app secret(小程序秘鑰,管理后臺(tái)可以獲得)換取 用戶唯一標(biāo)識(shí)openid 和 會(huì)話密鑰session_key。但每一次調(diào)用wx.login()都會(huì)更新微信接口服務(wù)器上的session_key。
/** * 我把這一步封裝成一個(gè)函數(shù),以后再調(diào)用那些需要登錄后才有權(quán)限訪問的后臺(tái)服務(wù)時(shí). * 可以使用使用這個(gè)函數(shù)操作,基本邏輯,還可以進(jìn)行擴(kuò)展 * @url : 開發(fā)者服務(wù)器登錄服務(wù)接口 可設(shè)置默認(rèn)值 * @key : 存入本地緩存的第三方自定義登錄session的鍵值 * @callback : 需要用到登錄服務(wù)的回調(diào)函數(shù)(或函數(shù)集合) */ function Login(key,url,callback){ // 首先使用wx.login獲取登錄憑證code并發(fā)送給開發(fā)者服務(wù)器 wx.login({ success: function(res) { if (res.code) { //發(fā)送code給開發(fā)者服務(wù)器以獲取session_key和openid wx.request({ url:url, data: { code: res.code }, //發(fā)送至開發(fā)者服務(wù)器成功 success: function(res) { //開發(fā)者服務(wù)器獲得session_key和openid成功并返回了 //第三方自定義session或者解密數(shù)據(jù)等json格式數(shù)據(jù)res給客戶端 if(res.has3rdSession){ //登錄成功,將第三方session存入本地緩存 console.log("登錄成功") wx.setStorageSync(key,res.3rdSession) //設(shè)置登錄標(biāo)識(shí)為true this.setData{ flag:true } //進(jìn)行后續(xù)回調(diào)處理 callback(res) .... } else{ //沒有返回第三方自定義session,登錄失敗 console.log("登錄失敗") .... } } }) } else { //沒有獲取到登錄憑證code,登錄失敗 console.log('登錄失??!' + res.errMsg) .... } } }) }
/** - 我把這一步封裝成一個(gè)函數(shù),以后再調(diào)用那些需要登錄后才有權(quán)限訪問的后臺(tái)服務(wù)時(shí). - 可以使用使用這個(gè)函數(shù)操作,基本邏輯,還可以進(jìn)行擴(kuò)展 - @url : 開發(fā)者服務(wù)器服務(wù)接口 - @key : 自己定義的session存儲(chǔ)在本地緩存中的鍵名 - @callback : 需要用到登錄服務(wù)的回調(diào)函數(shù)(或函數(shù)集合) - @others : 其他需要用到的數(shù)據(jù)等參數(shù) */ function doRequestWithSession(key,url,callback,others) { try { var value = wx.getStorageSync(key) if (value) { // 存在自定義登錄session,非首次登錄 // 查詢 用戶密鑰session_key是否過期 wx.checkSession({ success: function(){ //session_key 未過期,并且在本生命周期一直有效 //向開發(fā)者服務(wù)器發(fā)送自定義session查詢用戶信息 wx.request({ url: url, data: value, //本地緩存的自定義Session值 可以加上其他需要的數(shù)據(jù)others等 success: function(res) { if(res.hasSession){ //查詢成功,開發(fā)者服務(wù)器上有我們自定義的session //根據(jù)返回結(jié)果進(jìn)行對(duì)應(yīng)的操作,先判斷session是否過期 //如果我們自定義的session已經(jīng)過期 if(res.expired){ console.log("session過期,重新登錄") //設(shè)置登錄標(biāo)識(shí)為false this.setData{ flag:false } wx.login() //重新登錄 或者 返回錯(cuò)誤碼 .... } else{ //沒有過期,返回的結(jié)果則可以是用戶的相關(guān)信息 //進(jìn)行相關(guān)操作 登錄成功 console.log("歡迎回來") callback(res) .... } } else { //開發(fā)者服務(wù)器上沒有我們自定義的session,重新登錄 console.log("無此session,重新登錄") //設(shè)置登錄標(biāo)識(shí)為false this.setData{ flag:false } wx.login() //重新登錄 或者 返回錯(cuò)誤碼 .... } } }) }, fail: function(){ // session_key 已經(jīng)失效,需要重新執(zhí)行登錄流程 //設(shè)置登錄標(biāo)識(shí)為false this.setData{ flag:false } wx.login() //重新登錄 或者 返回錯(cuò)誤碼 .... } }) } else{ //本地緩存中沒有自定義的session登錄態(tài)信息,則進(jìn)行首次登錄或者后續(xù)處理 //設(shè)置登錄標(biāo)識(shí)為false this.setData{ flag:false } wx.login() //登錄 或者 返回錯(cuò)誤碼 .... } } catch (e) { // 異常處理 .... } }
if(this.data.flag){ //已經(jīng)登錄過,非首次登錄 doRequestWithSession(key,url,callback,others) .... } else{ //沒有登錄過,可以進(jìn)一步檢查本地緩存是否有3rdSession do other things .... } 3.獲取安全的原始數(shù)據(jù)在第一部分已經(jīng)說過敏感數(shù)據(jù)和開放數(shù)據(jù),可以用 wx.getUserInfo獲得開放數(shù)據(jù),但是沒有登錄獲取解密密鑰session_key是無法解密敏感數(shù)據(jù)的,所以開放數(shù)據(jù)中,沒有登錄的話,我們只能獲得用戶昵稱、頭像、城市、性別、國籍等,并沒有可以標(biāo)識(shí)用戶的唯一id。所以如何拿到我們的安全的原始數(shù)據(jù),只有:獲取開放數(shù)據(jù)——>獲得登錄權(quán)限,開發(fā)者服務(wù)器獲得密鑰session_key校驗(yàn)簽名解密數(shù)據(jù)——>返回解密數(shù)據(jù),包含有openid。偽代碼: a.wxml 文件: //wx.getUserInfo接口有調(diào)整,使用該接口將不再出現(xiàn)授權(quán)彈窗,要使用 <button>組件引導(dǎo)用戶主動(dòng)進(jìn)行授權(quán)操作,使用此接口要注意: //當(dāng)用戶未授權(quán)過,調(diào)用該接口將直接報(bào)錯(cuò);當(dāng)用戶授權(quán)過,可以使用該接口獲取用戶信息 //例子 <button open-type='getUserInfo' bindgetuserinfo='showUserInfo'>登錄</button> a.js 文件: Page({ data:{}, ... //點(diǎn)擊登錄按鈕后觸發(fā) showUserInfo:function(e){ //獲取需要解密的數(shù)據(jù) var encryptedData = e.detail.encryptedData /* *@key 第三方自定義登錄session存在本地緩存的key值 *@url 解密敏感數(shù)據(jù)的開發(fā)者服務(wù)器服務(wù)接口 *@callback 獲得解密數(shù)據(jù)后的回調(diào)函數(shù) *@encryptedData 當(dāng)前獲得的未解密數(shù)據(jù) */ doRequestWithSession(key,url,callback,encryptedData) }, }) 4.后臺(tái)后臺(tái)的服務(wù)有很多,可以做API平臺(tái)進(jìn)行統(tǒng)一管理:
其中的解密代碼示例 (官方4種語言版本:Python、php、c++、node): <?php class WXBizDataCrypt { private $appid; private $sessionKey; /** * 構(gòu)造函數(shù) * @param $sessionKey string 用戶在小程序登錄后獲取的會(huì)話密鑰 * @param $appid string 小程序的appid */ public function __construct( $appid, $sessionKey) { $this->sessionKey = $sessionKey; $this->appid = $appid; } /** * 檢驗(yàn)數(shù)據(jù)的真實(shí)性,并且獲取解密后的明文. * @param $encryptedData string 加密的用戶數(shù)據(jù) * @param $iv string 與用戶數(shù)據(jù)一同返回的初始向量 * @param $data string 解密后的原文 * * @return int 成功0,失敗返回對(duì)應(yīng)的錯(cuò)誤碼 */ 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"); } ?> 接觸不深 ,權(quán)當(dāng)記錄。錯(cuò)漏處還望多多指正~ |
工作日 8:30-12:00 14:30-18:00
周六及部分節(jié)假日提供值班服務(wù)