Flask與微信小程序登陸(後端)

開發微信小程序時,接入小程序的受權登陸能夠快速實現用戶註冊登陸的步驟,是快速創建用戶體系的重要一步。這篇文章將介紹 python + flask + 微信小程序實現用戶快速註冊登陸方案(本文主要進行後端邏輯的梳理,小程序端邏輯只寫了必要的部分,若有須要,請點擊鏈接閱讀官方開發文檔)html

官方給出的微信小程序登陸時序圖以下:python

img

這個流程分爲兩大部分:redis

  1. 小程序使用 wx.login() API 獲取 code,並由開發者後端服務器換取open_id 和 session_key,小程序使用 wx.getUserInfo() API 獲取 encryptedData 和 iv,而後將這三個信息發送給開發者服務器服務器。
  2. 開發者服務器獲取到 code、encryptedData和 iv 後,將 session_key 利用 encryptedData 和 iv 解密,在服務端獲取用戶信息。根據用戶信息返回 jwt 數據,完成登陸狀態。

小程序登陸流程梳理

1 小程序端調用wx.login

小程序經過**wx.login**獲取微信的 code,而後將這個 code 發送給開發者服務器。算法

返回值數據庫

屬性 類型 說明
code String 用戶容許登陸後,回調內容會帶上 code(有效期五分鐘)

2 判斷用戶是否受權

小程序端能夠經過 wx.getSetting 接口獲取用戶當前的受權狀態json

  • 若是用戶已經受權,則直接發起登陸請求
  • 若是用戶沒有受權,則調用 wx.authorize引導用戶關注公衆號 來得到受權。
  • 若是用戶不予受權,則登陸失敗。

3 小程序端訪問 wx.getUserInfo

小程序端調用 wx.getUserInfo API 來得到用戶信息(該接口的調用須要得到用戶受權)flask

接口success 時返回參數以下:小程序

參數名 類型 說明
userInfo OBJECT 用戶信息對象,不包含 openid 等敏感信息。
rawData String 不包括敏感信息的原始數據字符串,用於計算簽名。
signature String 使用 sha1( rawData + sessionkey ) 獲得字符串,用於校驗用戶信息
encryptedData String 包括敏感數據在內的完整用戶信息的加密數據,詳細見加密數據解密算法
iv String 加密算法的初始向量,詳細見加密數據解密算法

將這些第一步得到的js_code和這裏得到的 rawData, signature, encryptedData, iv一塊兒打包傳入開發者後端。segmentfault

4 開發者服務器訪問code2session

開發者服務器接收到 code 以後,會進行封裝處理,經過**code2Session**這個api接口來獲取真正須要的微信用戶的登陸態session_keyopenidunionid後端

  • 準確來講session_key纔是真正的微信登陸態信息,可是把 openidunionid加起來一塊兒理解,也能夠籠統地理解爲這些都是微信的登陸態信息。

請求參數

屬性 類型 默認值 必填 說明
appid string 小程序 appId
secret string 小程序 appSecret
js_code string 登陸時獲取的 code
grant_type string 受權類型,此處只需填寫 authorization_code

返回值(返回JSON數據包)

屬性 類型 說明
openid string 用戶惟一標識
session_key string 會話密鑰
unionid string 用戶在開放平臺的惟一標識符,在知足 UnionID 下發條件的狀況下會返回
errcode number 錯誤碼
errmsg string 錯誤信息

這時,服務器須要判斷返回的JSON數據包是否包含unionid:

  • 若是包含,則說明用戶已經受權(關注過同一主體公衆號,或者已經登陸太小程序在後端保存unionid)
  • 若是不包含,返回第1步,提醒用戶受權

5 開發者服務器校驗用戶信息

encryptedData 解密後爲如下 json 結構,詳見加密數據解密算法

{
    "openId": "OPENID",
    "nickName": "NICKNAME",
    "gender": GENDER,
    "city": "CITY",
    "province": "PROVINCE",
    "country": "COUNTRY",
    "avatarUrl": "AVATARURL",
    "unionId": "UNIONID",
    "watermark":
    {
        "appid":"APPID",
    "timestamp":TIMESTAMP
    }
}

解密腳本實例鏈接:https://res.wx.qq.com/wxdoc/dist/assets/media/aes-sample.eae1f364.zip

數據簽名校驗

爲了確保開放接口返回用戶數據的安全性,微信會對明文數據進行簽名。開發者能夠根據業務須要對數據包進行簽名校驗,確保數據的完整性。

  • 經過調用 wx.getUserInfo 藉口獲取數據時,接口會同時返回 rawData、signature,其中 signature = sha1( rawData + session_key )

數據簽名校驗具體步驟

  • 若是 code 爲空,返回登陸失敗。
  • 若是 code 不爲空,且 rawData 不爲空,須要進行簽名校驗:
    • 使用 codeappidapp_secret 請求code2session接口得到 session_keyopenid
      • 若是接口失敗,響應 ERR_SESSION_KEY_EXCHANGE_FAILED
    • 使用簽名算法經過 rawDatasession_key 計算簽名 signature2
    • 對比 signaturesignature2
      • 簽名不一致,響應 ERR_UNTRUSTED_RAW_DATA
      • 簽名一致,解析 rawDatawxUserInfo
        • openid 寫入到 wxUserInfo
        • (code, wxUserInfo) 緩存到 Redis
        • 更新用戶數據庫信息(unionid爲pk)
        • 進入下一環節
  • 若是 code 不爲空,但 rawData 爲空,從 Redis 根據 code 查詢緩存的用戶信息
    • 找到用戶信息,進入下一環節
    • 沒找到用戶信息(多是過時),響應 ERR_SESSION_EXPIRED

6 生成自定義登陸狀態(使用JWTtoken)

開發者服務器須要本身生成一個自定義的登陸態(例如業務 token或者 session)來保存這些微信服務器返回來的微信登陸態相關信息(session_keyopenidunionid),而且作關聯處理,而後返回給小程序客戶端。

  • 關聯處理就是你的自定義登陸態和微信的登陸態相關聯,這樣的話就不須要維護多個登陸態,只須要維護一個就能夠了。
  • 關聯處理以後須要將這個自定義登陸態信息保存起來,能夠放到數據庫或者本地文件或者 例如 redis 之類的緩存服務裏面,以便方便後續使用,而不須要每次都請求微信服務器(微信服務器對這個請求的頻率是有限制的)
  • 自定義登陸態的信息不只能夠包含 token,也能夠包含一些用戶權限信息,或者其餘信息,由於是自定義的登陸態,維護也是很自定義的。

7 小程序端將服務器端生成的token儲存

小程序客戶端接收到返回的自定義登陸態信息,從而判斷用戶是否登陸成功,登陸成功的話,就將自定義登陸態信息保存到本地的存儲。到這裏,登陸就完成了。

  • 本地的存儲能夠是微信小程序提供的 app.globaldata,也能夠是 localstoage,注意,小程序不支持 cookie
  • 保存到本地存儲的好處就是,後續使用的這個自定義登陸態就不須要再次跟服務器進行交互來獲取了,只須要調用本地存儲就好了,這裏是爲了優化性能和避免浪費資源。

8 小程序訪問業務接口邏輯

  1. 小程序客戶端訪問業務接口的時候,攜帶以前保存到本地存儲的自定義登陸態信息進行對開發者服務器(業務接口服務器)訪問。

  2. 開發者服務器的業務接口接收到請求,而且請求裏面攜帶了自定義的登陸態,經過校驗以後,會返回相關信息。

    校驗登陸是將小程序客戶端攜帶過來的自定義登陸態和開發者服務器緩存起來的自定義登陸態進行對比,會去確認是否和用戶的 openid或者 unionidsession_key 相匹配。

    • 若是匹配,就能夠立刻返回業務信息。
    • 若是不匹配,告知小程序客戶端沒法訪問業務接口,要求用戶從新登陸。
    • 若是匹配結果是自定義登陸態超時了,告知小程序客戶端須要從新運行登陸邏輯。
    • 若是是匹配結果是自定義登陸態沒有超時,可是微信登陸態超時了,那麼要求開發者服務器就會再次發起code2Session進行微信登陸態更新。

因爲咱們的小程序使用微信號做爲小程序的帳號,若是須要使用自定義的帳號,則須要再加上註冊的api和關聯帳號的邏輯。

流程總結

  • code 是微信用戶的登陸臨時憑證,是打開小程序登陸的時候獲取的只屬於這個微信用戶的登陸憑證,須要注意的是,這個登陸憑證只供微信小程序使用的。且同一個每一次登陸時得到的code都不一樣。這個 code 的存活時間通常是5分鐘左右,他的最大做用就是肯定是來源自哪個微信用戶來打開,是爲了後續生成一個微信登陸態 session_key而準備的。
  • session_key 是微信用戶在小程序裏面的登陸態信息,這是微信給這個用戶頒發的一個登陸 session。這個session 一直存活直到你關閉小程序。
    • 之前官方是返回固定的 expire_time 的,可是後面取消了,官方的解釋是:用戶越頻繁使用小程序,session_key有效期越長,初始有效期是3天,可是這個不必定是固定的,具體看業務需求,總的原則就是維護一個自定義登陸態,自定義登陸須要和微信登陸態關聯。
  • openId ,用戶在微信裏面的惟一標識,可是須要跟 unionid 進行一塊兒理解。
  • unioinId,若是開發者擁有多個移動應用、網站應用、和公衆賬號(包括小程序),可經過unionid來區分用戶的惟一性,由於只要是同一個微信開放平臺賬號下的移動應用、網站應用和公衆賬號(包括小程序),用戶的unionid是惟一的。換句話說,同一用戶,對同一個微信開放平臺下的不一樣應用,unionid是相同的。
    • 通常來講,openId 就是微信用戶的惟一標識,可是由於微信產品不少,因此會出現多個微信產品使用不一樣的 openId 來識別同一個用戶,因此建議是統一使用 unioinid 做爲用戶識別的依據,由於通常來講,通常的業務都會有公衆號,因此 unionid 使用頻率較高。
  • 3rd_session 是通常是指開發者服務器的登陸態,本文中並無使用這個概念,而是叫作自定義登陸態或者直接說JWTtoken,官方文檔或者其餘一些博客中會提到它。實際上他們是相同的概念。
    • 當小程序登陸態過時了,自定義登陸態沒過時的時候,那麼就須要在小程序打開的時候先執行一次wx.checkSession來檢查,若是過時了,就本地執行登陸操做,再讓開發者服務器跟微信服務器交互,獲取新的小程序登陸態,而後關聯到自定義登陸態。
    • 當小程序登陸態沒過時,自定義登陸態過時了的時候,那麼小程序客戶端訪問業務接口的時候,業務接口會告訴小程序客戶端,你的自定義登陸態超時了,而後小程序客戶端會從新執行登陸邏輯,而後通知開發者服務從新生成新的自定義登陸態,而後關聯以前還在使用的小程序登陸態。
    • 當兩者都同時過時的時候,那就確定要發起完整的從新登陸了。
    • 這樣的好處是自定義登陸態不須要重複建立,也能跟小程序登陸態一塊兒維護管理,達到資源合理利用的效果。
  • 通常自定義登陸態的管理都會使用相似 redis 之類的東西來進行管理的,這裏也涉及到一個自定義登陸態的緩存策略,緩存起來,在必定時間內不須要從新建立自定義登陸態,達到優化性能的效果。

登陸態的驗證

1 在每一次開啓小程序的時候須要檢查登陸態

若是每次打開小程序都須要用戶來登陸顯然是不合適的,若是用戶上一次的登陸態尚未過時,則應該視用戶爲已經登陸。若是過時,才須要用戶從新登陸。

有2種方式來作:

  1. 方式一:小程序打開的時候先檢查小程序本地是否有存儲的自定義登陸態,
    • 若是沒有,則表明是首次登陸,要自動執行完整的登陸流程,
    • 若是有,則須要判斷這個自定義登陸態是否過時,能夠是開發者服務器提供一個接口來檢查,也能夠是在這個自定義登陸態數據裏面加上過時時間,判斷是否過時。
      • 過時,則自動發起完整的登陸流程。
      • 不過時,就繼續使用本地保存的自定義登陸態。
  2. 方式二:小程序打開的時候先發起wx.checkSession檢查微信登陸態是否過時:
    1. 若是過時,則發起完整的登陸流程。
    2. 若是不過時,則繼續使用本地保存的自定義登陸態。(若是本地的自定義登陸態沒有的話,那麼也是要強制發起完整的登陸流程的)

2 在每次業務請求時須要驗證登陸態

某些業務須要只有用戶登陸狀態下才能夠執行,因此,咱們須要封裝一個api來驗證用戶時候登陸

實際上就是檢查一下微信和自定義的登陸態是否過時

img

參考連接

相關文章
相關標籤/搜索