评论

已解决。小程序获取手机号时,checkSession通过但是获取手机号解密失败

小程序获取手机号偶尔解密失败

  • 一开始我的处理方式是在页面直接用checkSession,我的session_key是在index.js登录的时候保存到storage,这里check回调的是“success”。
  • 但是把此时storage里面的session_key结合授权按钮的参数去进行解密是失败的,需要在当前的Page再登陆一次才能成功。
  • 不推荐把session_key存放在缓存。所以以上做法直接跳过。
  • 最后参考了一个朋友的做法,在Page onLoad的时候执行一次wx.login(),然后拿到新的session_key,再用此时的新key去解密就通了。或者改为请求解密之前执行一次登录,据说出问题的概率还是很大
  • 结尾补充:最后一种方法还有个问题要考虑,就是最好执行获取手机号之前再checkSession一下(尽管没啥用)。

问题源头,由于这个函数在校验session_key的时候,无论是过期的key还是新的key都是success,所以有了之后一些列的问题,session_key的状态没法把控

Page({
  data: {
  	currentSessionKey: null
  },
   
  onLoad: function(options) {
    /* do something*/
  	const here = this;
    // 执行登录确保session_key在线
    wx.login({
      success(res) {
        if (res.code) {
        // call()是我自己基于wx.request封装的一个请求函数工具,这里通过后端发送登录请求获得openid
          const data = call(userLogin, {
            code: res.code
          });
          data.then(obj => {
            if (!obj.error) {
              here.setData({ currentSessionKey: obj.result.session_key })
            }
          });
        }
      },
      fail(error) {
        throw error;
      }
    });
  },
   
  // 点击按钮获取手机号权限并解析<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber" bindtap='doMyAction'>获取手机号</button>
  getPhoneNumber: function (e) {
  	const { encryptedData, iv } = e.detail;
    const options = { encryptedData: encryptedData, iv: iv, sessionKey: this.data.currentSessionKey };
    here.doGetPhone(options);
  },
   
  doMyAction: function() {
    // 还可以做一些事情
  },
 
  doGetPhone: function (options) {
    const {
      sessionKey,
      encryptedData,
      iv
    } = options;
 
    const here = this;
    // 向服务器请求解密
    wx.request({
     // 这里是解密用的接口
      url: 'https://xxx.com/python/decrypt',
      method: 'POST',
      data: {
        sessionKey: sessionKey,
        encryptedData: encryptedData,
        iv: iv
      },
      success(res) {
        // 最终获取到用户数据,国家代号前缀、不带前缀的手机号。默认是不带前缀
        const { countryCode, purePhoneNumber } = res.data;
        here.pageForward(countryCode, purePhoneNumber);
      },
      fail(error) {
        console.log(error);
        here.pageForward();
      }
    })
  },
   
  pageForward: function(countryCode, purePhoneNumber) {
   // 获取成功后我是跳转到另一个页面
    wx.navigateTo({
      url: `/pages/person/index?phone=${purePhoneNumber}`
    })
  }
})
最后一次编辑于  2020-09-15  
点赞 5
收藏
评论

31 个评论

  • 逍遥哥
    逍遥哥
    2020-01-02

    我现在的解决方案是提示用户"请重试",很无奈

    2020-01-02
    赞同 6
    回复 1
    • 王华😄
      王华😄
      2022-04-19
      现在有更好的办法吗?@官方
      2022-04-19
      回复
  • 上善若水
    上善若水
    2019-12-12

    我也遇到这个问题了,错误信息只有:手机号解密失败,请官方出面解决一下吧!

    2019-12-12
    赞同 5
    回复
  • 曾威
    曾威
    2021-03-09

    官方能不能先解决这个bug,旧功能没完善天天整新功能

    2021-03-09
    赞同 4
    回复
  • JohnTitor
    JohnTitor
    2019-08-21

    我也遇到了,checkSession说没过期,后端说过期了。最后还是请求前再登录一次刷新session才成功

    2019-08-21
    赞同 3
    回复 1
    • bind
      bind
      2019-08-26
      好坑啊,只能在获取一次,checkSession没用
      2019-08-26
      回复
  • wekin
    wekin
    2021-10-21

    我也遇到了,checkSession就是个玩笑!!!!!!!!!!

    2021-10-21
    赞同 2
    回复
  • Raven R
    Raven R
    2021-01-01

    对于 wx.checkSession 这个没用的说法,我表示怀疑。

    当 checkSession 通过,然而 又遇到 后段使用 session_key 失效的同志们,

    要注意,wx.checkSession 是在什么时候执行的?

    目前看就是 encryptedData, iv 解密的时候失效,而这两个是在点击按钮后获得的,如果在按钮的 handler 里面检查session_key失效,又重新去wx.login了,这时候获得的 encryptedData, iv 对应的session_key 和 当前的session_key 是不统一的。于是解出来也是白板。虽然有时候这样做,还是可以运行通过的,那是因为在较短的时间内 连续获取的 session_key,似乎会是一样的。至少我测试下来是这样。这个较短的时间是多长?可能是一根烟的功夫。这种连续获取session_key情形是不是只在开发者工具中发生?不知道,也不重要,于是不用费劲去猜,跟没必要再深入试。

    那么如果 把检查 并且重新登录的逻辑 放在 页面的 onload 上行不行呢?

    行,但假如说用户长时间没有操作,那么还是要在 使用 session_key 之前 再检查一次。如果失效了,那么得引导一次重新wx.login。

    这部分逻辑 根本不可能是 if else 那么简单,实践中要复杂很多。要注意的是 已经获取到 encryptedData, iv 之后,发现 session_key 失效了,那就算重新login 也还是得重新获取 一次 encryptedData, iv。无法避免的 需要用户界面操作一次。

    我采用了比较简单的粗暴办法来应对这种情况。

    session_key 和用户的id等基本信息 组合成dict然后加密成 token,然后存入小程序客户端。发动服务端请求的时候 把token 发还,服务端解密后 取session_key出来用。

    自己封装一个 login的 promise 函数,在函数中如果token有效 那么就直接返回,无效,那么就重新登录。login 得是一个 promise函数,并且要暂存这个 promise,用来防止多次执行的登录,这样也会变换session_key。如果执行了,在那么直接返回暂存的 promise就行了。

    在page的 onload 事件上 绑定一个 装饰器,在装饰器内 使用封装好的函数,检查checkSession() 如果可用,那么就正常login,如果失效那么就强制登录(即使token有效也把它换掉)

    最后 app Lanuch 的时候 把 用户的 token 清掉。

    ps:这些问题 都是概率出现,弄完了以后要多花点时间测试,不要以为 自己刷了几下没事,那就真没事了。


    2021-01-01
    赞同 2
    回复 3
    • 纸飞机
      纸飞机
      2021-02-22
      哥们是描述的最明白的,这是重点「要注意的是 已经获取到 encryptedData, iv 之后,发现 session_key 失效了,那就算重新login 也还是得重新获取 一次 encryptedData, iv。无法避免的 需要用户界面操作一次。」
      2021-02-22
      回复
    • tiger
      tiger
      2021-11-25回复纸飞机
      是的,咋解决呢?大佬
      2021-11-25
      回复
    • 泡泡
      泡泡
      2023-08-16
      大佬咋解决啊
      2023-08-16
      回复
  • oldBoy
    oldBoy
    2020-12-19

    解密之前先wx.login()拿到session_key解密也不行,也会大概率的报解密失败

    2种原因

    1、是前端是最新的sesseion_key,后端不是

    2、后端是最新的,前端不是最新的session_key,搞的经常不同步,无奈,只能提醒重新获取

    2020-12-19
    赞同 2
    回复
  • peng
    peng
    2021-07-09

    解密救星来了,可以过去最近三次的用户信息加密key,在当前解密失败,调用此接口获取历史加密key来尝试解密:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/intetnet/internet.getUserEncryptKey.html

    2021-07-09
    赞同 1
    回复
  • 2019-11-22

    我也是按楼主这么做的,开发工具和公司所有手机都能正常获取手机号,但是还是有部分客户反馈无法获取手机号,要崩溃了

    2019-11-22
    赞同 1
    回复 1
    • Oliver
      Oliver
      2019-11-23
      1、看解密失败返回的错误信息是什么,绝大多数原因都可以在这里找到
      2、检查一下获取失败的手机是不是存在微信应用分身的情况
      3、小程序主体是不是海外的,这点具体要问官方了
      2019-11-23
      回复
  • d文意
    d文意
    2022-08-30

    我也遇到了,请问有没有好的解决

    2022-08-30
    赞同
    回复 3
    • 阿白
      阿白
      2022-09-28
      你好,解密失败的问题解决了吗?这边也遇到了同样的问题,第一次解密失败,同样的操作再来一次就好了。
      2022-09-28
      回复
    • d文意
      d文意
      2022-10-27回复阿白
      后台那边解决了
      2022-10-27
      回复
    • 阿白
      阿白
      2022-11-15回复d文意
      怎么解决的?有啥稳妥的方法吗?
      2022-11-15
      回复

正在加载...

登录 后发表内容