【更新說明】
由于微信小程式官方對相關API的改版,是以登入這塊功能流程有一些變動,是以最近再次更新了另一篇文章(附視訊說明和完整示例代碼),大家可與本文一起進行閱讀參考:
微信小程式接口改版後的登入和會話保持流程
提供使用者登入以及維護使用者的登入狀态,是一個擁有使用者系統的軟體應用普遍需要做的事情。像微信這樣的一個社交平台,如果做一個小程式應用,我們可能很少會去做一個完全脫離和舍棄連接配接使用者資訊的純工具軟體。
讓使用者登入,辨別使用者和擷取使用者資訊,以使用者為核心提供服務,是大部分小程式都會做的事情。我們今天就來了解下在小程式中,如何做使用者登入,以及如何去維護這個登入後的會話(Session)狀态。
在微信小程式中,我們大緻會涉及到以下三類登入方式:
- 自有的賬号注冊和登入
- 使用其他第三方平台賬号登入
- 使用微信賬号登入(即直接使用目前已登入的微信賬号來作為小程式的使用者進行登入)
第一和第二種方式是目前Web應用中最常見的兩種方式,在微信小程式中同樣可以使用,但是需要值的注意的是,小程式中沒有
Cookie
的機制,是以在使用這2種方式前,請确認你們或第三方的API是否需要依賴
Cookie
;還有小程式中也不支援HTML頁面,那些需要使用頁面重定向來進行登入的第三方API就需要改造,或不能用了。
我們今天主要來讨論一下第三種方式,即如何使用微信賬号進行登入,因為這種方式和微信平台結合最緊密,使用者體驗比較好。
登入流程
引用小程式官方文檔的登入流程圖,整個登入流程基本如下圖所示:
登入流程圖
該圖中,“小程式”指的就是我們使用小程式架構寫的代碼部分,“第三方伺服器”一般就是我們自己的背景服務程式,“微信伺服器”是微信官方的API伺服器。
下面我們來逐漸分解一下這個流程圖。
步驟1:在用戶端擷取目前登入微信使用者的 登入憑證(code)
登入憑證(code)
在小程式中登入的第一步,就是先擷取登入憑證。我們可以使用wx.login()方法并得到一個登入憑證。
我們可以在小程式的App代碼中發起登入憑證請求,也可以在其他任何Page頁面代碼中發起登入憑證請求,主要根據你小程式的實際需要。
App({
onLaunch: function() {
wx.login({
success: function(res) {
var code = res.code;
if (code) {
console.log('擷取使用者登入憑證:' + code);
} else {
console.log('擷取使用者登入态失敗:' + res.errMsg);
}
}
});
}
})
步驟2:将登入憑證發往你的服務端,并在你的服務端使用該憑證向微信伺服器換取該微信使用者的 唯一辨別(openid)
和 會話密鑰(session_key)
唯一辨別(openid)
會話密鑰(session_key)
首先,我們使用wx.request()方法,請求我們自己實作的一個背景API,并将登入憑證(code)攜帶過去,例如在我們前面代碼的基礎上增加:
App({
onLaunch: function() {
wx.login({
success: function(res) {
var code = res.code;
if (code) {
console.log('擷取使用者登入憑證:' + code);
// --------- 發送憑證 ------------------
wx.request({
url: 'https://www.my-domain.com/wx/onlogin',
data: { code: code }
})
// ------------------------------------
} else {
console.log('擷取使用者登入态失敗:' + res.errMsg);
}
}
});
}
})
你的背景服務(/wx/onlogin)接着需要使用這個傳遞過來的登入憑證,去調用微信接口換取openid和session_key,接口位址格式如下所示:
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
這裡是我使用了Node.js Express建構的背景服務的代碼,僅供參考:
router.get('/wx/onlogin', function (req, res, next) {
let code = req.query.code
request.get({
uri: 'https://api.weixin.qq.com/sns/jscode2session',
json: true,
qs: {
grant_type: 'authorization_code',
appid: '你小程式的APPID',
secret: '你小程式的SECRET',
js_code: code
}
}, (err, response, data) => {
if (response.statusCode === 200) {
console.log("[openid]", data.openid)
console.log("[session_key]", data.session_key)
//TODO: 生成一個唯一字元串sessionid作為鍵,将openid和session_key作為值,存入redis,逾時時間設定為2小時
//僞代碼: redisStore.set(sessionid, openid + session_key, 7200)
res.json({ sessionid: sessionid })
} else {
console.log("[error]", err)
res.json(err)
}
})
})
這段背景代碼成功執行的話,就可以得到openid和session_key。這個資訊就是目前微信賬戶在微信伺服器那邊的登入态了。
但是,為了安全方面的原因,請不要直接使用這些資訊作為你小程式的使用者辨別和session辨別回傳到小程式用戶端中去,我們應該在伺服器端做一層自己的session,将這個微信賬号登入态生成一個session id并維護在我們自己的session機制中,然後把這個session id派發到小程式用戶端作為session辨別來使用。
關于如何在伺服器端做這個session機制,我們現在一般采用鍵值對存儲工具來做,比如redis。我們為每個session生成一個唯一的字元串作為鍵,然後可以将session_key和openid作為值,存入redis中,為了安全,存入的時候還應設定一個逾時的時間。
步驟3:在用戶端儲存 sessionid
sessionid
開發Web應用的時候,在用戶端(浏覽器)中,我們通常将session id存放在cookie中,但是小程式沒有cookie機制,是以不能采用cookie了,但是小程式有本地的storage,是以我們可以使用storage來儲存sessionid,以供後續的背景API調用所使用。
在之後,調用那些需要登入後才有權限的通路的背景服務時,你可以将儲存在storage中的sessionid取出并攜帶在請求中(可以放在header中攜帶,也可以放在querystring中,或是放在body中,根據你自己的需要來使用),傳遞到背景服務,背景代碼中擷取到該sessionid後,從redis中查找是否有該sessionid存在,存在的話,即确認該session是有效的,繼續後續的代碼執行,否則進行錯誤處理。
這是一個需要session驗證的背景服務示例,我的sessionid是放在header中傳遞的,是以在這個示例中,是從請求的header中擷取sessionid:
router.get('/wx/products/list', function (req, res, next) {
let sessionid = req.header("sessionid")
let sessionVal = redisStore.get(sessionid)
if (sessionVal) {
// 執行其他業務代碼
} else {
// 執行錯誤處理
}
})
好了,通過微信賬号進行小程式登入和狀态維護的簡單流程就是這樣,了解這些知識點之後,再基于此進行後續的開發就會變得更容易了。
另外,騰訊前端團隊也開源了他們封裝的相關庫Wafer,可以借鑒和使用。
- 服務端SDK: wafer-node-session
- 小程式端SDK: wafer-client-sdk
感謝閱讀我的文章,如有疑問或寫錯的地方請不吝留言賜教。
一斤代碼的《微信小程式》相關教程文章 一斤代碼的《從程式設計小白到全棧開發》系列教程文章