讓使用者登錄,標識使用者和獲取使用者訊息,以使用者為核心提供服務,是大部分小程式都會做的事情。我們今天就來了解下在小程式中,如何做使用者登錄,以及如何去維護這個登入後的會話(Session)狀態。 【相關學習推薦:小程式開發教學】
在微信小程式中,我們大致會牽涉到以下三類登入方式:
第一和第二種方式是目前Web應用中最常見的兩種方式,在微信小程式中同樣可以使用,但是需要值的注意的是,小程式中沒有Cookie
的機制,所以在使用這2種方式前,請確認你們或第三方的API是否需要依賴Cookie
;還有小程式中也不支援HTML頁面,那些需要使用頁面重定向來進行登入的第三方API就需要改造,或不能用了。
我們今天主要來討論第三種方式,即如何使用微信帳號進行登錄,因為這種方式和微信平台結合最緊密,用戶體驗比較好。
引用小程式官方文件的登入流程圖,整個登入流程基本上如下圖所示:
該圖中,「小程式」指的就是我們使用小程式框架寫的程式碼部分,「第三方伺服器」一般就是我們自己的後台服務程序,「微信伺服器」是微信官方的API伺服器。
下面我們來逐步分解一下這個流程圖。
步驟一:在客戶端取得目前登入微信使用者的登入憑證(code)
在小程式中登入的第一步,就是先取得登入憑證。我們可以使用wx.login()
方法並且得到一個登入憑證。
我們可以在小程式的App程式碼中發起登入憑證要求,也可以在其他任何Page頁面程式碼中發起登入憑證要求,主要根據你小程式的實際需求。
步驟二:將登入憑證發送到你的服務端,並在你的服務端使用該憑證向微信伺服器換取該微信使用者的唯一識別(openid)和會話金鑰(session_key )
首先,我們使用wx.request()方法,請求我們自己實作的一個後台API,並將登入憑證(code)攜帶過去,例如在我們前面程式碼的基礎上增加:
你的後台服務接著需要使用這個傳遞過來的登入憑證,去呼叫微信介面換取openid和session_key
我們先來介紹下openid,用過公眾號的童鞋應該對這個標識都不陌生了,在公眾平台裡,用來標識每個用戶在訂閱號、服務號、小程式這三種不同應用的唯一標識,也就是說每個用戶在每個應用的openid都是不一致的,所以在小程式裡,我們可以用openid來識別使用者的唯一性。
那麼session_key是用來幹嘛的呢?有了使用者標識,我們就需要讓該使用者登入,那麼 session_key 就保證了目前使用者進行會話操作的有效性,而這個session_key是微信服務端給我們派發的。也就是說,我們可以用這個識別來間接維護我們小程式使用者的登入態,那麼這個session_key是怎麼拿到的呢?我們需要在自己的服務端請求微信提供的第三方介面https://api.weixin.qq.com/sns/jscode2session
從這幾個參數,我們可以看出,要請求這個介面必須先呼叫wx.login()來取得到使用者目前會話的code。那為什麼我們要在服務端來請求這個介面呢?其實是出於安全性的考量,如果我們在前端透過request呼叫此接口,就不可避免的需要將我們小程式的appid和小程式的secret暴露在外部,同時也將微信服務端下發的session_key暴露給“有心之人”,這對我們的業務安全造成極大的風險。除了需要在服務端進行session_key的獲取,我們還需要注意兩點:
session_key和微信派發的code是一一對應的,同一code只能換取一次session_key。每次呼叫wx.login()
,都會下發一個新的code和對應的session_key,為了確保使用者體驗和登入態的有效性,開發者需要清楚使用者需要重新登入時才去調用wx.login()
session_key是有失效的,即使是不呼叫wx.login,session_key也會過期,過期時間跟使用者使用小程序的頻率成正相關,但具體的時間長短開發者和使用者都是獲取不到的
步驟三:產生3rd_session
前面說過透過session_key 來「間接」維護登入態,所謂間接,也就是我們需要自己維護用戶的登入態訊息,這裡也是考慮到安全性因素,如果直接使用微信服務端派發的session_key來作為業務方的登錄態使用,會被“有心之人”用來獲取用戶的敏感信息,比如 wx.getUserInfo()
這個介面呢,就需要session_key來配合解密微信使用者的敏感資訊。
那麼我們如果產生自己的登入態標識呢,這裡可以使用幾種常見的不可逆的雜湊演算法,例如md5、sha1等,將產生後的登入態標識(這裡我們統稱為'skey ')返回給前端,並在前端維護這份登錄態標識(一般是存入storage)。而在服務端呢,我們會把生成的skey存在用戶對應的資料表中,前端透過傳遞skey來存取用戶的資訊。
步驟四:在客戶端保存Session ID
開發Web應用程式的時候,在客戶端(瀏覽器)中,我們通常會將Session ID存放在cookie中,但是小程式沒有cookie機制,所以不能採用cookie了,但是小程式有本地的storage,所以我們可以使用storage來保存Session ID,以供後續的後台API呼叫所使用。
在之後,當呼叫那些需要登入後才有權限存取的後台服務時,你可以將儲存在storage中的Session ID取出並攜帶在請求中(可以放在header中攜帶,也可以放在querystring中,或放在body中,根據你自己的需求來使用),傳遞到後台服務,後台程式碼中取得到該Session ID後,從redis中查找是否有該Session ID存在,存在的話,即確認該session是有效的,繼續後續的程式碼執行,否則進行錯誤處理。
前面我們將skey存入前端的storage裡,每次進行用戶資料請求時都會帶上skey,那麼如果此時session_key過期呢?所以我們需要呼叫到wx.checkSession()
這個API來校驗目前session_key是否已經過期,這個API並不需要傳入任何有關session_key的資訊參數,而是微信小程式自己去調自己的服務來查詢使用者最近一次產生的session_key是否過期。如果目前session_key過期,就讓使用者來重新登錄,更新session_key,並將最新的skey存入使用者資料表中。
步驟五:支援emoji表情儲存
如果需要將使用者微信名存入資料表中,那麼就確認資料表及資料列的編碼格式。因為使用者微信名可能會包含emoji圖標,而常用的UTF8編碼只支援1-3個字節,emoji圖標剛好是4個位元組的編碼進行儲存。
這裡有兩種方式(以mysql為例):
1.設定儲存字元集
在mysql5.5.3版本後,支持將資料庫及資料表和資料列的字元集設定為utf8mb4 ,因此可在/etc/my.cnf 設定預設字元集編碼及服務端編碼格式
[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
設定完預設字元集編碼及服務端字元集編碼,如果是對已經存在的表格和欄位進行編碼轉換,則需要執行下面幾個步驟:
設定資料庫字元集為utf8mb4
ALTER DATABASE 数据库名称 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
設定資料表字元集為utf8mb4
ALTER TABLE 数据表名称 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
設定資料列欄位字元集為utf8mb4
ALTER TABLE 数据表名称 CHANGE 字段列名称 VARCHAR(n) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
這裡的COLLATE 指的是排序字元集,也就是用來對儲存的字元進行排序與比較的, utf8mb4 常用的collation有兩種: utf8mb4_unicode_ci 和utf8mb4_general_ci ,一般建議使用utf8mb4_unicode_ci ,因為它是基於標準的Unicode Collation Algorithm(UCA) 來排序的,可以在各種語言進行精確排序。這兩種排序方式的具體差異可以參考: What's the difference between utf8_general_ci and utf8_unicode_ci
2.透過使用sequelize對emoji字元進行編碼入庫,使用時再進行解碼#這裡是sequelize的配置,可參考 Sequelize文件
{ dialect: 'mysql', // 数据库类型 dialectOptions: { charset: 'utf8mb4', collate: "utf8mb4_unicode_ci" }, }
附:後台程式碼(tp5)
#################################
更多程式相關知識,請造訪:程式設計入門! !
以上是小程式如何做使用者登入?如何維護登入狀態?的詳細內容。更多資訊請關注PHP中文網其他相關文章!