微信小程序登录流程解析
小程序可以通過(guò)微信官方提供的登錄能力方便地獲取微信提供的用戶(hù)身份標(biāo)識(shí)openid,快速建立小程序內(nèi)的用戶(hù)體系。
登錄流程時(shí)序:
1、首先,調(diào)用 wx.login獲取code ,判斷用戶(hù)是否授權(quán)讀取用戶(hù)信息,調(diào)用wx.getUserInfo讀取用戶(hù)數(shù)據(jù) 。
2、然后,由于小程序后臺(tái)授權(quán)域名無(wú)法授權(quán)微信的域名,所以我們只能通過(guò)我們自己的服務(wù)器去調(diào)用微信服務(wù)器去獲取用戶(hù)信息。
3、然后,故我們將wx.login獲取code 和wx.getUserInfo 獲取的encryptedData與iv 通過(guò)wx.request 請(qǐng)求傳入后臺(tái)。
4、然后,調(diào)用接口獲取登錄憑證(code)進(jìn)而換取用戶(hù)登錄態(tài)信息,包括用戶(hù)的唯一標(biāo)識(shí)(openid) 及本次登錄的 會(huì)話(huà)密鑰(session_key)。
5、然后,用戶(hù)數(shù)據(jù)的加解密通訊需要依賴(lài)會(huì)話(huà)密鑰完成,code 換取 session_key,這是一個(gè) HTTPS 接口,開(kāi)發(fā)者服務(wù)器使用登錄憑證 code 獲取 session_key 和 openid。
6、最后,其中 session_key 是對(duì)用戶(hù)數(shù)據(jù)進(jìn)行加密簽名的密鑰。為了自身應(yīng)用安全,session_key 不應(yīng)該在網(wǎng)絡(luò)上傳輸。
該圖中,“小程序”指的就是我們使用小程序框架寫(xiě)的代碼部分,“第三方服務(wù)器”一般就是我們自己的后臺(tái)服務(wù)程序,“微信服務(wù)器”是微信官方的API服務(wù)器。
下面我們來(lái)逐步分解一下這個(gè)流程圖。
步驟一:在客戶(hù)端獲取當(dāng)前登錄微信用戶(hù)的登錄憑證(code)
在小程序中登錄的第一步,就是先獲取登錄憑證。我們可以使用wx.login()方法并得到一個(gè)登錄憑證。
我們可以在小程序的App代碼中發(fā)起登錄憑證請(qǐng)求,也可以在其他任何Page頁(yè)面代碼中發(fā)起登錄憑證請(qǐng)求,主要根據(jù)你小程序的實(shí)際需要。
步驟二:將登錄憑證發(fā)往你的服務(wù)端,并在你的服務(wù)端使用該憑證向微信服務(wù)器換取該微信用戶(hù)的唯一標(biāo)識(shí)(openid)和會(huì)話(huà)密鑰(session_key)
首先,我們使用wx.request()方法,請(qǐng)求我們自己實(shí)現(xiàn)的一個(gè)后臺(tái)API,并將登錄憑證(code)攜帶過(guò)去,例如在我們前面代碼的基礎(chǔ)上增加:
你的后臺(tái)服務(wù)接著需要使用這個(gè)傳遞過(guò)來(lái)的登錄憑證(code),去調(diào)用微信接口換取openid和session_key
我們先來(lái)介紹下openid,用過(guò)公眾號(hào)的童鞋應(yīng)該對(duì)這個(gè)標(biāo)識(shí)都不陌生了,在公眾平臺(tái)里,用來(lái)標(biāo)識(shí)每個(gè)用戶(hù)在訂閱號(hào)、服務(wù)號(hào)、小程序這三種不同應(yīng)用的唯一標(biāo)識(shí),也就是說(shuō)每個(gè)用戶(hù)在每個(gè)應(yīng)用的openid都是不一致的,所以在小程序里,我們可以用openid來(lái)標(biāo)識(shí)用戶(hù)的唯一性。
那么session_key是用來(lái)干嘛的呢?有了用戶(hù)標(biāo)識(shí),我們就需要讓該用戶(hù)進(jìn)行登錄,那么 session_key 就保證了當(dāng)前用戶(hù)進(jìn)行會(huì)話(huà)操作的有效性,這個(gè)session_key是微信服務(wù)端給我們派發(fā)的。也就是說(shuō),我們可以用這個(gè)標(biāo)識(shí)來(lái)間接地維護(hù)我們小程序用戶(hù)的登錄態(tài),那么這個(gè)session_key是怎么拿到的呢?我們需要在自己的服務(wù)端請(qǐng)求微信提供的第三方接口 https://api.weixin.qq.com/sns/jscode2session
從這幾個(gè)參數(shù),我們可以看出,要請(qǐng)求這個(gè)接口必須先調(diào)用wx.login()來(lái)獲取到用戶(hù)當(dāng)前會(huì)話(huà)的code。那么為什么我們要在服務(wù)端來(lái)請(qǐng)求這個(gè)接口呢?其實(shí)是出于安全性的考量,如果我們?cè)谇岸送ㄟ^(guò)request調(diào)用此接口,就不可避免的需要將我們小程序的appid和小程序的secret暴露在外部,同時(shí)也將微信服務(wù)端下發(fā)的session_key暴露給“有心之人”,這就給我們的業(yè)務(wù)安全帶來(lái)極大的風(fēng)險(xiǎn)。除了需要在服務(wù)端進(jìn)行session_key的獲取,我們還需要注意兩點(diǎn):
session_key和微信派發(fā)的code是一一對(duì)應(yīng)的,同一code只能換取一次session_key。每次調(diào)用wx.login(),都會(huì)下發(fā)一個(gè)新的code和對(duì)應(yīng)的session_key,為了保證用戶(hù)體驗(yàn)和登錄態(tài)的有效性,開(kāi)發(fā)者需要清楚用戶(hù)需要重新登錄時(shí)才去調(diào)用wx.login()
session_key是有失效性的,即便是不調(diào)用wx.login,session_key也會(huì)過(guò)期,過(guò)期時(shí)間跟用戶(hù)使用小程序的頻率成正相關(guān),但具體的時(shí)間長(zhǎng)短開(kāi)發(fā)者和用戶(hù)都是獲取不到的
步驟三:通過(guò)不可逆的哈希算法將session_key生成登錄態(tài)標(biāo)識(shí)3rd_session(應(yīng)該就是token)
前面說(shuō)過(guò)通過(guò) session_key 來(lái)“間接”地維護(hù)登錄態(tài),所謂間接,也就是我們需要 自己維護(hù)用戶(hù)的登錄態(tài)信息 ,這里也是考慮到安全性因素,如果直接使用微信服務(wù)端派發(fā)的session_key來(lái)作為業(yè)務(wù)方的登錄態(tài)使用,會(huì)被“有心之人”用來(lái)獲取用戶(hù)的敏感信息,比如wx.getUserInfo()這個(gè)接口呢,就需要session_key來(lái)配合解密微信用戶(hù)的敏感信息。
那么我們?nèi)绻勺约旱牡卿洃B(tài)標(biāo)識(shí)呢,這里可以使用幾種常見(jiàn)的不可逆的哈希算法,比如md5、sha1等,將生成后的登錄態(tài)標(biāo)識(shí)(這里我們統(tǒng)稱(chēng)為'skey')返回給前端,并在前端維護(hù)這份登錄態(tài)標(biāo)識(shí)(一般是存入storage)。而在服務(wù)端呢,我們會(huì)把生成的skey存在用戶(hù)對(duì)應(yīng)的數(shù)據(jù)表中,前端通過(guò)傳遞skey來(lái)存取用戶(hù)的信息。
步驟四:在客戶(hù)端的本地storage保存Session ID(應(yīng)該就是3rd_session,即token)
開(kāi)發(fā)Web應(yīng)用的時(shí)候,在客戶(hù)端(瀏覽器)中,我們通常將Session ID存放在cookie中,但是小程序沒(méi)有cookie機(jī)制,所以不能采用cookie了,但是小程序有本地的storage,所以我們可以使用storage來(lái)保存Session ID,以供后續(xù)的后臺(tái)API調(diào)用所使用。
在之后,調(diào)用那些需要登錄后才有權(quán)限訪問(wèn)的后臺(tái)服務(wù)時(shí),你可以將保存在storage中的Session ID取出并攜帶在請(qǐng)求中(可以放在header中攜帶,也可以放在querystring中,或是放在body中,根據(jù)你自己的需要來(lái)使用),傳遞到后臺(tái)服務(wù),后臺(tái)代碼中獲取到該Session ID后,從redis中查找是否有該Session ID存在,存在的話(huà),即確認(rèn)該session是有效的,繼續(xù)后續(xù)的代碼執(zhí)行,否則進(jìn)行錯(cuò)誤處理。
前面我們將skey存入前端的storage里,每次進(jìn)行用戶(hù)數(shù)據(jù)請(qǐng)求時(shí)會(huì)帶上skey,那么如果此時(shí)session_key過(guò)期呢?所以我們需要調(diào)用到wx.checkSession()這個(gè)API來(lái)校驗(yàn)當(dāng)前session_key是否已經(jīng)過(guò)期,這個(gè)API并不需要傳入任何有關(guān)session_key的信息參數(shù),而是微信小程序自己去調(diào)自己的服務(wù)來(lái)查詢(xún)用戶(hù)最近一次生成的session_key是否過(guò)期。如果當(dāng)前session_key過(guò)期,就讓用戶(hù)來(lái)重新登錄,更新session_key,并將最新的skey存入用戶(hù)數(shù)據(jù)表中。
步驟五:支持emoji表情存儲(chǔ)
如果需要將用戶(hù)微信名存入數(shù)據(jù)表中,那么就確認(rèn)數(shù)據(jù)表及數(shù)據(jù)列的編碼格式。因?yàn)橛脩?hù)微信名可能會(huì)包含emoji圖標(biāo),而常用的UTF8編碼只支持1-3個(gè)字節(jié),emoji圖標(biāo)剛好是4個(gè)字節(jié)的編碼進(jìn)行存儲(chǔ)。
代碼如下:
//app.js
App({
onLaunch: function () {
// 登錄
wx.login({
success: res => { // 在客戶(hù)端通過(guò)wx.login()方法獲取res.code
// 發(fā)送 res.code 到后臺(tái)換取 openId 驗(yàn)證平臺(tái)賬號(hào)是否登錄綁定過(guò)
var that = this;
wx.request({ // 你的服務(wù)器攜帶res.code去請(qǐng)求微信服務(wù)器獲取openId和session_key
method: 'GET',
url: this.globalData.serverApi + "/mobileApi/user/checkBind?code="+res.code,
header: {
'content-type': 'application/json'
},
success (res) {
if(res.data.code == 301){
//未登錄
var openId = res.data.openId;
wx.reLaunch({
url: '/pages/login/login?openId='+openId
})
}else if(res.data.code == 1){
//已登錄
that.globalData.userInfo = res.data.userInfo;
that.globalData.token = res.data.token;
var menuList = res.data.menuList;
wx.setStorageSync('menuList', menuList);
}else if(res.data.code == 0){
//獲取openId失敗
wx.showToast({
title: res.data.msg,
icon: 'none',
duration: 2000
})
}
// 由于 checkBind 是網(wǎng)絡(luò)請(qǐng)求,可能會(huì)在 Page.onLoad 之后才返回
// 所以此處加入 callback 以防止這種情況
if (that.checkBindCallback) {
that.checkBindCallback(res)
}
}
})
}
})
})
總結(jié)
以上是生活随笔為你收集整理的微信小程序登录流程解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 编程命名法则
- 下一篇: ES6、7、8常用新特性总结(超实用)