全面瞭解微信用戶體系

近年來,“觸手可及”——無需下載即可使用的特性,引發了小程序開發的熱潮,已經吸引了150萬開發者的入駐,形成了一個由百萬應用構成,覆蓋200多個細分行業,日活高達2個多億的生態圈。在小程序這個完備社會中,用戶的身份識別是如何做到的呢?今天讓我們一起探究一下吧。

ps:如不是特別熟悉小程序,可以先閱讀一下先前的兩篇文章~(微信小程序測試方案(上)、微信小程序測試方案(下))

OpenID的定義

OpenID是微信公眾號或者微信小程序等多種應用中的普通用戶的唯一標識,類似於國內現實社會中的身份證號,通過身份證號的官方唯一性,來保證個人的身份識別。

正如現實中身份證號不能私人篡改,OpenID也不能由微信用戶隨意修改,因為它不是開發者或者普通用戶自己生成的,而是前端通過微信提供的API接口 wx.login({})獲得的一個登錄憑證,再用這個登錄憑證去調用開發者後臺的接口,後臺再通過這個登錄憑證去調用微信的方法,獲取到OpenID。

unionID的定義

既然OpenID已經可以滿足用戶身份識別的功能了,為什麼還需要引入unionID呢?

當開發者擁有多個移動應用、網站應用、和公眾賬號(包括小程序)時,同一用戶在不同應用下的 OpenID 是不一樣的。在這種情形下,很顯然OpenID已經不能勝任用戶身份的識別了,那怎麼保證用戶身份的唯一性呢?

unionID是個不二選擇,只要是在同一主體下面,unionID這個值永遠是一樣的,無論該主體下面存在多少應用,因此可以通過unionID來判斷是否為同一個人,自然就實現了多個應用賬戶的打通。

ID的選擇

理論上講,當公司產品有App、小程序、公眾號等多種應用矩陣時,用 unionID 是更好的選擇,通過unionID的唯一性可以保證同一用戶不會產生多個OpenID,進而為統一的賬戶體系建設打下堅實的基礎,但是unionID的獲取需要遵循微信官方的限制:

1. 必須使用一個專用按鈕控件讓用戶主動點擊,否則無法彈出授權彈窗

2. 需要說明獲取相關權限的用途,並且用戶必須點擊「允許」同意小程序獲取公開信息

但是以上2步可能導致用戶的流失,而OpenID可以通過靜默方式獲取,對用戶的干擾相對較少,所以開發者需要根據現實情況評估選擇最合適的ID。

ID的獲取

小程序可以通過微信官方提供的登錄能力方便地獲取微信提供的用戶身份標識,快速建立小程序內的用戶體系。

登錄時序如下所示:

全面瞭解微信用戶體系

1. 調用 wx.login() 獲取 臨時登錄憑證code ,並回傳到開發者服務器。

2.調用 auth.code2Session 接口(GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code),換取 用戶唯一標識 OpenID會話密鑰 session_key,滿足特殊條件時會一併返回 UnionID。

3. 開發者服務器可以根據用戶標識來生成自定義登錄態,用於後續業務邏輯中前後端交互時識別用戶身份。


友情提示:

  1. appid為小程序id,secret為小程序密鑰(AppSecret),在登錄https://mp.weixin.qq.com/後,通過設置->開發設置可以獲得前面兩個參數,js_code就是步驟1中獲得的臨時登錄憑證,而grant_type為固定值authorization_code。
  2. 會話密鑰 session_key 是對用戶數據進行加密簽名的密鑰。為了應用自身的數據安全,開發者服務器不應該把會話密鑰下發到小程序,也不應該對外提供這個密鑰。
  3. 臨時登錄憑證 code 只能使用一次。
  4. 上面步驟2中獲取UnionID的特殊條件如下所示:a) 如果開發者帳號下存在同主體的公眾號,並且該用戶已經關注了該公眾號。b) 如果開發者帳號下存在同主體的公眾號或移動應用,並且該用戶已經授權登錄過該公眾號或移動應用。

除了通過上述登錄方式獲取UnionID,還有哪些其他方式呢?

  1. 調用接口 wx.getUserInfo,從解密數據中獲取 UnionID。注意本接口需要用戶授權,請開發者妥善處理用戶拒絕授權後的情況。
  2. 用戶在小程序(暫不支持小遊戲)中支付完成後,開發者可以直接通過getPaidUnionId接口獲取該用戶的 UnionID,無需用戶授權。注意:本接口僅在用戶支付完成後的5分鐘內有效,請開發者妥善處理。
  3. 小程序端調用雲函數時,如果開發者帳號下存在同主體的公眾號,並且該用戶已經關注了該公眾號,可在雲函數中通過 cloud.getWXContext 獲取 UnionID。
  4. 小程序端調用雲函數時,如果開發者帳號下存在同主體的公眾號或移動應用,並且該用戶已經授權登錄過該公眾號或移動應用,也可在雲函數中通過 cloud.getWXContext 獲取 UnionID。

PS2中的會話密鑰session_key是存在有效性的,因此如果遇到因為 session_key 不正確而校驗簽名失敗或解密失敗,需要注意以下幾點:

1. wx.login 調用時,用戶的 session_key 可能會被更新而致使舊 session_key 失效(刷新機制存在最短週期,如果同一個用戶短時間內多次調用 wx.login,並非每次調用都導致 session_key 刷新)。開發者應該在明確需要重新登錄時才調用 wx.login,及時通過 auth.code2Session 接口更新服務器存儲的 session_key。

2. 微信不會把 session_key 的有效期告知開發者。我們會根據用戶使用小程序的行為對 session_key 進行續期。用戶越頻繁使用小程序,session_key 有效期越長。

3. 開發者在 session_key 失效時,可以通過重新執行登錄流程獲取有效的 session_key。使用接口 wx.checkSession可以校驗 session_key 是否有效,從而避免小程序反覆執行登錄流程。

4. 當開發者在實現自定義登錄態時,可以考慮以 session_key 有效期作為自身登錄態有效期,也可以實現自定義的時效性策略。

除了可以獲取用戶唯一標識ID(加密信息,需要通過上面的session_key進行解密),還可以獲取哪些用戶公開信息(UserInfo)呢?

微信暱稱、微信頭像圖片的URL(如果用戶沒有頭像,URL會是空的,如果用戶更換了頭像,原有頭像的URL會失效)、用戶性別(未知、男性、女性)、所在國家、所在省份、所在城市和語言(英文、簡體中文、繁體中文)。

ID獲取Demo
接下來,讓我們通過一段代碼demo來演示一下ID獲取的主要流程吧。

1.微信小程序客戶端調用 wx.login()接口獲取登錄憑證(code)並將登錄憑證發送給開發者服務器以獲取OpenID

//1、調用微信登錄接口,獲取code
wx.login({
 success: function (r) {
 var code = r.code;//登錄憑證
 if (code) {
 //2、發送登錄憑證以獲取OpenID
 wx.request({
 url: 'https://xxxx.com/login', //自己服務登錄地址
 method: 'post',
 header: {
 'content-type': 'application/json'
 },
 data: {code: code},
 success: function (data) {
 console.log('獲取用戶OpenID成功');
 },
 fail: function () {
 console.log('獲取用戶OpenID失敗');
 }
 
 })

 } else {
 console.log('獲取用戶登錄態失敗!' + r.errMsg)
 }
 },
 fail: function () {
 callback(false)
 }
})

2.服務器發送code到微信服務器獲取openid(用戶唯一標識)和session_key(會話密鑰)

/**
 * 獲取用戶OpenID
 * @param code 用戶允許登錄後,回調內容會帶上 code(有效期五分鐘),開發者需要將 code 發送到開發者服務器後臺,使用code 換取 session_key api,將 code 換成 openid 和 session_key
 * @return
*/
 @ResponseBody
 @RequestMapping(value = "/login", method = RequestMethod.POST)
 public Map login(String encryptedData, String iv, String code) {

 Map map = new HashMap();
 //登錄憑證不能為空
 if (code == null || code.length() == 0) {
 map.put("status", 0);
 map.put("msg", "code 不能為空");
 return map;
 }

 //小程序唯一標識 (在微信小程序管理後臺獲取)
 String wxspAppid = "xxxxxxxxxxxxxx";
 //小程序的 app secret (在微信小程序管理後臺獲取)
 String wxspSecret = "xxxxxxxxxxxxxx";
 //授權(必填)
 String grant_type = "authorization_code";


 //向微信服務器 使用登錄憑證 code 獲取 session_key 和 openid
 //請求參數
 String params = "appid=" + wxspAppid + "&secret=" + wxspSecret + "&js_code=" + code + "&grant_type=" + grant_type;
 //發送請求
 String sr = HttpRequest.sendGet("https://api.weixin.qq.com/sns/jscode2session", params);
 //解析相應內容(轉換成json對象)
 JSONObject json = JSONObject.fromObject(sr);
 //獲取會話密鑰(session_key)
 String session_key = json.get("session_key").toString();
 //用戶的唯一標識(openid)
 String openid = (String) json.get("openid");
 map.put("status", 0);
 map.put("openid",openid); map.put("msg", "獲取openid成功");
 return map; 
 }

以上介紹了微信生態下用戶的身份標識,並依據主要步驟,進行了簡單代碼實現,那這一切對於一名測試的意義在哪裡呢?

除了從前端直接發起的黑盒鏈路測試,下游的接口測試必然繞不開以OpenID作為入參,而OpenID的值顯然依賴於與微信後臺的交互,這必然需要在上述代碼中加入相關測試輔助代碼,當然可以通過尋求開發的輔助來實現這個目的,但這就嚴重依賴於開發的支持力度,為什麼不自己實現呢。

除此之外,還可以有目的的瞭解整個流程的限制,自然而然可以圍繞相關限制來進行案例的設計,從而更容易的發現實現中的缺陷,達到事倍功半的目的,一個測試人員的價值必然會放大,進而擴大了個人的影響力。

以上就是關於微信賬戶體系的介紹,希望能使你對這塊有了一點認識。更多主題,請持續關注哦~


分享到:


相關文章: