小程序授权手机号失败,提示”请重新授权手机号“的分析与理解

2,550 阅读2分钟

问题

维护公司代码,发现授权手机号,有时会失败,提示“请重新授权手机号”。

去和后端沟通,后端说我code失效。

但是code有效时间为5分钟。【官方】

打印出获取到code到发送给后端的时间,发现几乎在一分钟内完成,不会是codo超过五分钟失效。

代码

(注:此代码是错误案例❌)

<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
  getPhoneNumber (e) {
      //授权手机号,用户点击确认
    if ('getPhoneNumber:ok' === e.detail.errMsg) {
        //调用wx.login获取code
        wx.login({
            success: function(res) {	
                console.log('login接口获取的code', res.code, '当前时间', new Date())
                //传给后端进行解密
                getPhoneNo(res.code, e)
            }
	})
    } else {
    ...
    }
  }
  
  //后端解密接口
  getPhoneNo () {
  ...
  console.log('getPhoneNo接口入参的code', code, '当前时间', new Date())
  ...
  }
打印出的结果

image.png

获取到的code与传给后端的code一致,并且在有效期内

那么,为什么还会 授权失败呢?

原来官方文档已经写的很清楚了

小程序官方文档 /开放能力 /用户信息 /获取手机号 (点击查看官方文档)

在回调中调用 wx.login 登录,可能会刷新登录态。此时服务器使用 code 换取的 sessionKey 不是加密时使用的 sessionKey,导致解密失败。建议开发者提前进行 login;或者在回调中先使用 checkSession 进行登录态检查,避免 login 刷新登录态。

我对此的理解是:

① 获取用户手机号授权 → ② 用户点击确定 → ③ 微信对开放数据做签名和加密处理 → ④ 返回给前端 → ⑤ 前端将 数据 密文 密文串 发送给后端 → ⑥ 后端去微信服务器解密获取明文信息

如图:开放数据校验与解密 (点击查看官方文档)

image.png

所以,在执行wx.login之前,先检查一下登录态wx.checkSession

  getPhoneNumber (e) {
      //授权手机号,用户点击确认
    if ('getPhoneNumber:ok' === e.detail.errMsg) {
        wx.checkSession({
            success (res) {
                //session_key 未过期,并且在本生命周期一直有效
                //不传code给后端,让后端自己从缓存中去拿session_key
		getPhoneNo('', e, callback)
             },
            fail () {
                // session_key 已经失效,需要重新执行登录流程
                wx.login({
                   ...
                })
            }
	})
    } else {
    ...
    }
  }

官方wx.login 调用时,用户的 session_key 可能会被更新而致使旧 session_key 失效(刷新机制存在最短周期,如果同一个用户短时间内多次调用 wx.login,并非每次调用都导致 session_key 刷新)。开发者应该在明确需要重新登录时才调用 wx.login,及时通过 auth.code2Session 接口更新服务器存储的 session_key。

模拟session_key失效

image.png