全面了解微信用户体系

近年来,“触手可及”——无需下载即可使用的特性,引发了小程序开发的热潮,已经吸引了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的值显然依赖于与微信后台的交互,这必然需要在上述代码中加入相关测试辅助代码,当然可以通过寻求开发的辅助来实现这个目的,但这就严重依赖于开发的支持力度,为什么不自己实现呢。

除此之外,还可以有目的的了解整个流程的限制,自然而然可以围绕相关限制来进行案例的设计,从而更容易的发现实现中的缺陷,达到事倍功半的目的,一个测试人员的价值必然会放大,进而扩大了个人的影响力。

以上就是关于微信账户体系的介绍,希望能使你对这块有了一点认识。更多主题,请持续关注哦~


分享到:


相關文章: