收藏
评论

关于小程序获取手机号解密失败的踩坑历程

小程序中获取微信手机号的前提条件这里贴一个链接,各位同学自己看

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html


主要说说为什么会解密失败,主要有以下两点原因

  1. 微信服务器报错

  2. 你解密的姿势错了


对于第一点,比较少见,如果出现了,嗯 ,坐着等死就行了


解密失败一般是由于你的 sessionKey 失效导致的,而sessionKey 由 wx.login 这个api先获取code, 再由我们的后台拿这个code向微信服务器请求获得。code有效期五分钟。


上面的链接中有这样一句话


注意

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

这句话这么理解呢,打个比方,假设你第一次调用wx.login获取的为 sessionKey_1,在它的有效期内,你再去获取一个加密数据 encryptedData_1,这时候你用sessionKey_1去解密encryptedData_1就可以正常解密。

但是在获取encryptedData_1的时候会有个回调函数,如果你在这个回调函数里又调了一次wx.login,获取了 sessionKey_2,这时候登录态可能会被刷新,加密encryptedData_1时使用的sessionKey_1就会失效,再去解密encryptedData_1就会有很高的几率解密失败。至于为什么不会百分百刷新登录态,鬼知道这逻辑是怎么写的。

贴上我的部分代码(只贴获取手机号的部分,其他逻辑请根据自己产品业务酌情参考)

const app = getApp();


Page({

    data: {
        code: "",
    },
 
    // 获取手机号
    getPhoneAndLogin: function(e){
        let that = this;
        // console.log(e);
 
        if (e.detail.errMsg !== "getPhoneNumber:ok"){
            return;
        }
 
        wx.showLoading({
            mask: true,
        })
 
        // 检查登录态是否过期
        wx.checkSession({
            success(res) {
                // session_key 未过期,并且在本生命周期一直有效
                // console.log(res);

 

                wx.request({
                    url: app.globalData.apiUrl + '**********',
                    data: {
                        code: that.data.code,
                        encryptedData: e.detail.encryptedData,
                        iv: e.detail.iv,
                    },
                    method: "POST",
                    success: res => {
                        // console.log(res);                  
                    },
                    fail: res => {
                        
                        wx.showToast({
                            icon: "none",
                            title: '服务器繁忙',
                        })
                    },
                    complete: res => {
                        wx.hideLoading();
                    }
                })
            },
            fail(err) {
                // session_key 已经失效,需要重新执行登录流程

             

                wx.login({
                    success: res => {
                        that.data.code = res.code
                    }
                })
            }
        })
    },
 
    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        let that = this;
        // console.log(options);
 
        wx.login({
            success: res =>{
                that.data.code = res.code
            }
        })
    },
 
})
 



以上,如果有问题欢迎各位大佬指正



最后一次编辑于  2018-11-28
收藏

3 个评论

  • July
    July
    2019-05-29

    有个问题:用checkSession检查session_key即使没过期,也会导致解析失败。

    我之前就是使用checkSession检查session_key是否失效,没失效直接解密,会出现解析失败的情况;后来改成了每次onload时执行wx.login拿到session_key,再去获取手机号,这种情况下解析失败的就几乎没遇到过

    2019-05-29
    赞同 1
    回复 2
    • Z
      Z
      2019-05-30

      最近在重写登录模块的时候发现,获取手机号完成后再用同样的code去解密重新执行一遍流程会解密失败,且几率是百分百,但是check的时候却没有返回错误信息,就很迷

      2019-05-30
      回复
    • July
      July
      2019-05-30回复Z

      所以checkSession感觉没啥用(或者我们没有真正理解checkSession的使用),我已经放弃使用check了,都是每次onload时获取session_key,🤦‍♀️

      2019-05-30
      回复
  • 回响
    回响
    2021-10-18

    它那不是说在回调中调用才会刷新吗

    2021-10-18
    赞同
    回复
  • 对方正在输入...🚉
    对方正在输入...🚉
    2018-11-28

    应该是一个sessionKey会对应一个encryptedData,拿电话的时候你别从回调里面拿,先掉一个wx.login,然后在wx.login的回调里去拿电话号码不就可以保证这个sessionkey对应的就是这个encryptedData了么。

    2018-11-28
    赞同
    回复 5
    • Z
      Z
      2018-11-28

      当然可以在每次获取一个encryptedData之前获取一个sessionKey,但是sessionKey在它的有效期内是可以重复使用的,只要你不去重新获取,另外小程序内点击按钮才能获取号码的机制注定不能在wx.login的回调里去拿电话号码,只能事先将sessionKey存起来备用

      2018-11-28
      回复
    • 对方正在输入...🚉
      对方正在输入...🚉
      2018-11-28

       看了一下,貌似还真是。。那怎么保证能100%解析成功?

      2018-11-28
      回复
    • Z
      Z
      2018-11-28回复对方正在输入...🚉

      我是在小程序启动时或者页面加载时调用wx.login获取code存起来,需要用的时候再和加密数据一起传给后台,传之前检查一下登录态是否过期

      2018-11-28
      回复
    • Sunflower⁶₆⁶₆⁶₆
      Sunflower⁶₆⁶₆⁶₆
      2018-11-29回复Z

      像你说的这样的话,登录状态如果过期了,岂不是又得重新点击去获取手机号,这样的话,点击获取手机号点了两次了

      2018-11-29
      回复
    • Z
      Z
      2018-11-29回复Sunflower⁶₆⁶₆⁶₆

      是的,但是也可以在进入获取手机号的页面的时候检查一下登录态啊,之后获取手机号后再检查一下。

      这也是无奈之举,获取手机号的那个操作是固定的,没办法拦截用户点击获取手机号button按钮之前的动作

      2018-11-29
      回复
登录 后发表内容