微信小程序用戶登錄和登錄態(tài)維護(hù)的實(shí)現(xiàn)
讓用戶登錄,標(biāo)識(shí)用戶和獲取用戶信息,以用戶為核心提供服務(wù),是大部分小程序都會(huì)做的事情。我們今天就來(lái)了解下在小程序中,如何做用戶登錄,以及如何去維護(hù)這個(gè)登錄后的會(huì)話(Session)狀態(tài)。
在微信小程序中,我們大致會(huì)涉及到以下三類登錄方式:
- 自有的賬號(hào)注冊(cè)和登錄;
- 使用其他第三方平臺(tái)賬號(hào)登錄;
- 使用微信賬號(hào)登錄(即直接使用當(dāng)前已登錄的微信賬號(hào)來(lái)作為小程序的用戶進(jìn)行登錄)。
第一和第二種方式是目前Web應(yīng)用中最常見的兩種方式,在微信小程序中同樣可以使用,但是需要值的注意的是,小程序中沒(méi)有Cookie
的機(jī)制,所以在使用這2種方式前,請(qǐng)確認(rèn)你們或第三方的API是否需要依賴Cookie
;還有小程序中也不支持HTML頁(yè)面,那些需要使用頁(yè)面重定向來(lái)進(jìn)行登錄的第三方API就需要改造,或不能用了。
我們今天主要來(lái)討論一下第三種方式,即如何使用微信賬號(hào)進(jìn)行登錄,因?yàn)檫@種方式和微信平臺(tái)結(jié)合最緊密,用戶體驗(yàn)比較好。
登錄流程
引用小程序官方文檔的登錄流程圖,整個(gè)登錄流程基本如下圖所示:
該圖中,“小程序”指的就是我們使用小程序框架寫的代碼部分,“第三方服務(wù)器”一般就是我們自己的后臺(tái)服務(wù)程序,“微信服務(wù)器”是微信官方的API服務(wù)器。
下面我們來(lái)逐步分解一下這個(gè)流程圖。
步驟一:在客戶端獲取當(dāng)前登錄微信用戶的登錄憑證(code)
在小程序中登錄的第一步,就是先獲取登錄憑證。我們可以使用wx.login()
方法并得到一個(gè)登錄憑證。
我們可以在小程序的App代碼中發(fā)起登錄憑證請(qǐng)求,也可以在其他任何Page頁(yè)面代碼中發(fā)起登錄憑證請(qǐng)求,主要根據(jù)你小程序的實(shí)際需要。
步驟二:將登錄憑證發(fā)往你的服務(wù)端,并在你的服務(wù)端使用該憑證向微信服務(wù)器換取該微信用戶的唯一標(biāo)識(shí)(openid)和會(huì)話密鑰(session_key)
首先,我們使用wx.request()方法,請(qǐng)求我們自己實(shí)現(xiàn)的一個(gè)后臺(tái)API,并將登錄憑證(code)攜帶過(guò)去,例如在我們前面代碼的基礎(chǔ)上增加:
你的后臺(tái)服務(wù)接著需要使用這個(gè)傳遞過(guò)來(lái)的登錄憑證,去調(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ào)、服務(wù)號(hào)、小程序這三種不同應(yīng)用的唯一標(biāo)識(shí),也就是說(shuō)每個(gè)用戶在每個(gè)應(yīng)用的openid都是不一致的,所以在小程序里,我們可以用openid來(lái)標(biāo)識(shí)用戶的唯一性。
那么session_key是用來(lái)干嘛的呢?有了用戶標(biāo)識(shí),我們就需要讓該用戶進(jìn)行登錄,那么 session_key 就保證了當(dāng)前用戶進(jìn)行會(huì)話操作的有效性,這個(gè)session_key是微信服務(wù)端給我們派發(fā)的。也就是說(shuō),我們可以用這個(gè)標(biāo)識(shí)來(lái)間接地維護(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)獲取到用戶當(dāng)前會(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,為了保證用戶體驗(yàn)和登錄態(tài)的有效性,開發(fā)者需要清楚用戶需要重新登錄時(shí)才去調(diào)用wx.login()
- session_key是有失效性的,即便是不調(diào)用wx.login,session_key也會(huì)過(guò)期,過(guò)期時(shí)間跟用戶使用小程序的頻率成正相關(guān),但具體的時(shí)間長(zhǎng)短開發(fā)者和用戶都是獲取不到的
步驟三:生成3rd_session
前面說(shuō)過(guò)通過(guò) session_key 來(lái)“間接”地維護(hù)登錄態(tài),所謂間接,也就是我們需要 自己維護(hù)用戶的登錄態(tài)信息 ,這里也是考慮到安全性因素,如果直接使用微信服務(wù)端派發(fā)的session_key來(lái)作為業(yè)務(wù)方的登錄態(tài)使用,會(huì)被“有心之人”用來(lái)獲取用戶的敏感信息,比如wx.getUserInfo()
這個(gè)接口呢,就需要session_key來(lái)配合解密微信用戶的敏感信息。
那么我們?nèi)绻勺约旱牡卿洃B(tài)標(biāo)識(shí)呢,這里可以使用幾種常見的不可逆的哈希算法,比如md5、sha1等,將生成后的登錄態(tài)標(biāo)識(shí)(這里我們統(tǒng)稱為'skey')返回給前端,并在前端維護(hù)這份登錄態(tài)標(biāo)識(shí)(一般是存入storage)。而在服務(wù)端呢,我們會(huì)把生成的skey存在用戶對(duì)應(yīng)的數(shù)據(jù)表中,前端通過(guò)傳遞skey來(lái)存取用戶的信息。
步驟四:在客戶端保存Session ID
開發(fā)Web應(yīng)用的時(shí)候,在客戶端(瀏覽器)中,我們通常將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存在,存在的話,即確認(rèn)該session是有效的,繼續(xù)后續(xù)的代碼執(zhí)行,否則進(jìn)行錯(cuò)誤處理。
前面我們將skey存入前端的storage里,每次進(jìn)行用戶數(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)查詢用戶最近一次生成的session_key是否過(guò)期。如果當(dāng)前session_key過(guò)期,就讓用戶來(lái)重新登錄,更新session_key,并將最新的skey存入用戶數(shù)據(jù)表中。
步驟五:支持emoji表情存儲(chǔ)
如果需要將用戶微信名存入數(shù)據(jù)表中,那么就確認(rèn)數(shù)據(jù)表及數(shù)據(jù)列的編碼格式。因?yàn)橛脩粑⑿琶赡軙?huì)包含emoji圖標(biāo),而常用的UTF8編碼只支持1-3個(gè)字節(jié),emoji圖標(biāo)剛好是4個(gè)字節(jié)的編碼進(jìn)行存儲(chǔ)。
這里有兩種方式(以mysql為例):
1.設(shè)置存儲(chǔ)字符集
在mysql5.5.3版本后,支持將數(shù)據(jù)庫(kù)及數(shù)據(jù)表和數(shù)據(jù)列的字符集設(shè)置為 utf8mb4 ,因此可在 /etc/my.cnf 設(shè)置默認(rèn)字符集編碼及服務(wù)端編碼格式
[client] default-character-set=utf8mb4 [mysql] default-character-set=utf8mb4 [mysqld] character-set-client-handshake = FALSE character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci
設(shè)置完默認(rèn)字符集編碼及服務(wù)端字符集編碼,如果是對(duì)已經(jīng)存在的表和字段進(jìn)行編碼轉(zhuǎn)換,需要執(zhí)行下面幾個(gè)步驟:
設(shè)置數(shù)據(jù)庫(kù)字符集為 utf8mb4
ALTER DATABASE 數(shù)據(jù)庫(kù)名稱 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
設(shè)置數(shù)據(jù)表字符集為 utf8mb4
ALTER TABLE 數(shù)據(jù)表名稱 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
設(shè)置數(shù)據(jù)列字段字符集為 utf8mb4
ALTER TABLE 數(shù)據(jù)表名稱 CHANGE 字段列名稱 VARCHAR(n) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
這里的 COLLATE 指的是排序字符集,也就是用來(lái)對(duì)存儲(chǔ)的字符進(jìn)行排序和比較的, utf8mb4 常用的collation有兩種: utf8mb4_unicode_ci 和 utf8mb4_general_ci ,一般建議使用 utf8mb4_unicode_ci ,因?yàn)樗腔跇?biāo)準(zhǔn)的 Unicode Collation Algorithm(UCA) 來(lái)排序的,可以在各種語(yǔ)言進(jìn)行精確排序。這兩種排序方式的具體區(qū)別可以參考: What's the difference between utf8_general_ci and utf8_unicode_ci
2.通過(guò)使用sequelize對(duì)emoji字符進(jìn)行編碼入庫(kù),使用時(shí)再進(jìn)行解碼
這里是sequelize的配置,可參考 Sequelize文檔
{ dialect: 'mysql', // 數(shù)據(jù)庫(kù)類型 dialectOptions: { charset: 'utf8mb4', collate: "utf8mb4_unicode_ci" }, }
附:后臺(tái)代碼(tp5)
到此這篇關(guān)于微信小程序用戶登錄和登錄態(tài)維護(hù)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)小程序用戶登錄和登錄態(tài)維護(hù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Javascript attachEvent傳遞參數(shù)的辦法
找了半天找到的解決辦法,看介紹說(shuō)是javascript的閉包問(wèn)題,導(dǎo)致得不能直接讀取外部的那個(gè)函數(shù),不然就所有傳遞的參數(shù)都變?yōu)樽詈笠粋€(gè)了。2009-12-12JS獲取表格視圖所選行號(hào)的ids過(guò)程解析
這篇文章主要介紹了JS獲取表格視圖所選行號(hào)的ids過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02javascript Array.prototype.slice的使用示例
javascript Array.prototype.slice除了常見的從某個(gè)數(shù)組中抽取出新的數(shù)組外,它還有一些其他的用法,下面就為大家講這些妙用2013-11-11實(shí)現(xiàn)lightBox時(shí)的樣式與行為分離減少JS
本教程旨在實(shí)現(xiàn)lightBox時(shí)的樣式與行為分離,減少JS在各方面(全屏遮蔽、ie6中遮蔽select、雙向居中、高度自適應(yīng)內(nèi)容等)的工作。2009-07-07javascript實(shí)現(xiàn)簡(jiǎn)單小鋼琴有聲彈奏效果
用HTML5+javascript實(shí)現(xiàn)的小鋼琴,按下鋼琴鍵上的相應(yīng)字母用或用鼠標(biāo)點(diǎn)擊鋼琴鍵發(fā)聲,javascript代碼包含了對(duì)鼠標(biāo)按下、移動(dòng)和松開,以及鍵盤按下的事件監(jiān)聽2024-02-02js實(shí)現(xiàn)內(nèi)容顯示并使用json傳輸數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)內(nèi)容顯示并使用json傳輸數(shù)據(jù)的方法,感興趣的小伙伴們可以參考一下2016-03-03JS基于正則實(shí)現(xiàn)數(shù)字千分位用逗號(hào)分隔的方法
這篇文章主要介紹了JS基于正則實(shí)現(xiàn)數(shù)字千分位用逗號(hào)分隔的方法,涉及javascript正則表達(dá)式操作數(shù)字的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-06-06JS字符串累加Array不一定比字符串累加快(根據(jù)電腦配置)
言歸正傳:性能差異較大的機(jī)器運(yùn)行結(jié)果會(huì)RT 出現(xiàn)大的差異,為了保險(xiǎn)起見。還是推薦使用Array 來(lái)進(jìn)行字符串拼接操作2012-05-05JS版網(wǎng)站風(fēng)格切換實(shí)例代碼
這個(gè)網(wǎng)站風(fēng)格切換除了帶記憶功能外,還可設(shè)定保持時(shí)間,比如5天-180天,過(guò)了時(shí)間就自動(dòng)恢復(fù)到默認(rèn)樣式表。2008-10-10