微信應用的一個很大的優勢就在於使用過程中是不需要進行注冊和顯式登錄的,大部分問題基本上可以一鍵解決。但是在授權、登錄和獲取用戶信息的過程中都發生了哪些事情,今天我們就來討論一下。這篇文章主要分析以下幾個問題:
- 授權和登錄的意義
- session_key 的作用
- unionId 的作用,有哪些獲取途徑
- 在應用中如何保存用戶登錄態
一、授權和登錄的意義
首先必須要明白,授權和登錄實際上是兩個操作。
1.1 授權
那授權的作用是啥呢?從小程序官方文檔中我們可以看到授權操作只需通過wx.authorize() 接口便可以完成,以下是文檔中對授權操作的描述:
提前向用戶發起授權請求。調用后會立刻彈窗詢問用戶是否同意授權小程序使用某項功能或獲取用戶的某些數據,但不會實際調用對應接口【比如說在調用獲取用戶信息接口前,需要用戶授權,但在授權過程中並不調用 獲取用戶信息接口】。如果用戶之前已經同意授權,則不會出現彈窗,直接返回成功。
也就是說,授權過程實際上只是在小程序前端獲得了操作部分wx 接口的訪問許可,這個過程實際上是不會與開發者服務器發生任何關系的。那這些訪問許可包含哪些內容呢?再來看微信官方提供的scope 列表:

注:新版api已廢棄wx.authorize()
1.2 登錄
所謂的登錄就是要讓開發者服務器知道當前的用戶是誰?在傳統的web 應用中,我們必須要讓用戶輸入賬號和密碼才能實現登錄操作。但是在微信應用中,我們可以通過微信服務器來完成這個操作,獲取到與當前用戶對應的唯一標志(openId),具體操作實現流程如下:
wx.login()用來做登錄的方法,調用接口獲取登錄憑證,code發送給后端用於置換session_key和openid等數據。每個用戶相對於每個微信應用(公眾號或者小程序)的openId 是唯一的,也就是說一個用戶相對於不同的微信應用會存在不同的openId。

這是小程序官方的一張登錄流程圖,現在就來解讀一下這個流程
- 前端wx.login()獲取code,調用后端接口,將得到的code發送到后端
- 后端調用微信接口,用appid+appsecret+code發送過去,置換到session_key+openid,以前是不能置換unionid的,但是現在在滿足以下條件可以置換到unionid
- 微信開放平台下存在同主體的App、公眾號、小程序
- 用戶關注了某個相同主體公眾號,或曾經在某個相同主體App、公眾號上進行過微信登錄授權 同時滿足以上兩個條件就能拿到用戶unionid,這樣一來,就能在wx.login()准確識別出用戶是誰
- 自定登錄態與openid和session_key關聯,實際就是生成一個與openid,session_key關聯的token,下發給前端。
- 前端將后端下發的token存入緩存,在后面的接口請求中帶上自定登錄態
以上就是小程序的整個登錄流程,可以看到其實並不是一定要wx.getUserInfo()才能拿到用戶的信息,在特定的條件下,通過wx.login()的調用拿到unionId也能后端數據庫里拿到用戶信息。登錄過程中涉及session_key和unionId,於是又引出了下面的問題。
二、session_key 的作用
那么,session_key在登錄的過程中或者登錄完成后起什么作用呢?一起來看一下。
2.1 wx.getUserInfo
首先來看一下wx.getUserInfo 這個api:

在設置withCredentials 屬性為true 的情況下,這個api 可以拿到encryptedData,iv 等敏感信息,encryptedData 需要使用session_key 進行解密,解密后可以拿到的數據如下:

也就是說,session_key的作用之一是將小程序前端從微信服務器獲取到的encryptedData 解密出來,獲取到openId 和unionId等信息
但是在1.2登錄過程中可以看到開發者服務器是能夠直接拿到用戶的openId信息,而且unionId 也是有其他獲取途徑,所以session_key 在這里的作用看起來有點雞肋。
2.2 getPhoneNumber
session_key 更重要的作用大概體現在獲取用戶手機方面(可能還包含其他敏感信息獲取api)。

從文檔中可以看到getPhoneNumber 返回的用戶數據是加密過的,只有使用session_key才能解密,而小程序前端沒有session_key,所以無法獲取到用戶的手機,只能傳到開發者服務器進行處理。
三、unionId 的作用,有哪些獲取途徑?
3.1、UnionID機制說明
如果同一公司擁有多個移動應用、網站應用、和公眾帳號(包括小程序),可通過unionid來區分用戶的唯一性,因為只要是同一個微信開放平台帳號下的移動應用、網站應用和公眾帳號(包括小程序),用戶的unionid是唯一的。換句話說,同一用戶,對同一個微信開放平台下的不同應用,unionid是相同的。
Tip:unionid 用於識別同一主體下不同賬號之間的用戶。舉例說明:就是公司有A訂閱號,B服務號,同一個人關注A和B,會得到不同的OPENID,但是會得到相同的unionid。這樣就可以識別到相同的用戶,用於不同賬號之間打通用戶關系。
3.2、UnionID獲取途徑
必須有一個微信開放平台賬號綁定了至少一個微信公眾賬號或者網站應用或者小程序,否則UnionID返回null。綁定了開發者帳號的小程序,可以通過下面3種途徑獲取UnionID。
方法一:調用接口wx.getUserInfo,從解密數據中獲取UnionID。注意本接口需要用戶授權,請開發者妥善處理用戶拒絕授權后的情況。
方法二:如果開發者帳號下存在同主體的公眾號,並且該用戶已經關注了該公眾號。開發者可以直接通過wx.login獲取到該用戶UnionID,無須用戶再次授權。
方法三:如果開發者帳號下存在同主體的公眾號或移動應用,並且該用戶已經授權登錄過該公眾號或移動應用。開發者也可以直接通過wx.login獲取到該用戶UnionID,無須用戶再次授權。
四、在應用中如何保存用戶登錄態
保存用戶登錄態,一直以來都有兩種解決方案:前端保存和后端保存。
4.1 后端保存
在1.2 步驟③ 中寫session 的時候可以直接設定過期時間,定期通知小程序前端重新進行登錄(wx.login)。
4.2 前端保存
因為session_key 存在時效性問題(畢竟是用來查看敏感信息),而小程序前端可以通過wx.checkSession() 來檢查session_key 是否過期。所以可以通過這個來作為保存用戶登錄態的機制,這也是小程序文檔中推薦的方法:

文章源地址:https://cloud.tencent.com/developer/article/1766827