小程序授权返回小程序解密失败

一、问题描述:

小程序获取手机号的代码,在 getphonenumber 回调函数里,先调用 login 拿到 code,再用 code 请求后端的接口。会有一定概率返回小程序解密失败。代码如下:

<template>
    <button
      open-type="getPhoneNumber"
      lang="zh_CN"
      @getphonenumber="onGetphonenumber">
      获取手机号
    </button>
</template>

<script>
import { GrantPhoneNumber } from "@/api";

export default {
  methods: {
    //获取手机号
    onGetphonenumber(e) {
      if (e.detail.errMsg.includes("ok")) {
        //用户授权了手机号
        wx.login({
          success: res => {
            let code = res.code;
            GrantPhoneNumber({
              code,
              encryptedData: encodeURIComponent(e.detail.encryptedData),
              iv: encodeURIComponent(e.detail.iv)
            })
              .then(res => {
                console.log("GrantPhoneNumber:res :>> ", res);
              })
              .catch(err => {
                console.log("GrantPhoneNumber:err :>> ", err);
              })
          }
        });
      }
    }
  }
};
</script>

二、原因:

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

小程序授权返回小程序解密失败

三、解决方法:

看了文档的描述,解决小程序解密失败有两种方式:

  • 一种方法是提前拿到 code,也就是在 getphonenumber 回调之前,先调用 login 拿到 code,再用 code 请求后端的接口。
  • 另一种方法是在请求后端接口的时候先判断 code 是否过期。没过期的话,去请求后端接口,否则重新获取 code。

这里我用的是第一种,通过 login 拿到的 code 的有效期,有的说是5分钟,有的说是3分钟。结合自身业务的使用场景,同时也为了以防万一,我在代码里设置了 code 的有效期是1分钟,1分钟后,如果用户没有登录的操作,则重新去获取 code,完整代码如下:

<template>
    <button
      class="btnClass"
      open-type="getPhoneNumber"
      lang="zh_CN"
      @getphonenumber="onGetphonenumber"
      :style="btnStyle">
      获取手机号
    </button>
</template>

<script>
import { GrantPhoneNumber } from "@/api";

export default {
  data() {
    return {
      code: "", //小程序的code
      isLost: false //code是否失效
    };
  },
  onLoad() {
    //防止出现解密失败,提前进行Login
    wx.login({
      success: res => {
      	console.log("phone_login:res :>> ", res);
        this.code = res.code;
      }
    });
    let interval = setInterval(() => {
      if ( wx.getStorageSync("userPhone")) {
        //如果用户已经登录成功 清除定时器
        clearInterval(interval);
      } else {
        //一分钟后让code失效,重新获取
        this.isLost = true;
      }
    }, 60000);
  },
  methods: {
    //获取手机号
    onGetphonenumber(e) {
      if (e.detail.errMsg.includes("ok")) {
        //用户授权了手机号
        let _this = this;
        if (!this.isLost) {
          //code没过期 进行授权
          _this.phoneHandler(e.detail.encryptedData, e.detail.iv);
        } else {
          //code已过期 重新拿code再授权
          wx.login({
            success: res => {
              console.log("phoneHandler_code已过期 重新拿code :>> ", res);
              this.code = res.code;
              _this.phoneHandler(e.detail.encryptedData, e.detail.iv);
            }
          });
        }
      }
    },
    //授权手机号
    phoneHandler(encryptedData, iv) {
      GrantPhoneNumber({
        code: this.code,
        encryptedData: encodeURIComponent(encryptedData),
        iv: encodeURIComponent(iv)
      })
        .then(res => {
          console.log("GrantPhoneNumber:res :>> ", res);
          // 本地缓存存一份
           wx.setStorageSync("userPhone", JSON.stringify(res.phone));
        })
        .catch(err => {
          console.log("GrantPhoneNumber:err :>> ", err);
        })
    }
  }
};
</script>

参考资料:

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用uniapp开发的抖音小程序授权获取手机号的完整代码: 1. 在页面中引入抖音小程序授权组件 ```html <template> <view> <phone-auth :visible.sync="isShowPhoneAuth" @success="onPhoneAuthSuccess" @cancel="onPhoneAuthCancel" /> <button @click="showPhoneAuth">授权手机号</button> </view> </template> <script> import PhoneAuth from '@/components/phone-auth' export default { components: { PhoneAuth }, data() { return { isShowPhoneAuth: false } }, methods: { showPhoneAuth() { this.isShowPhoneAuth = true }, onPhoneAuthSuccess(phoneNumber) { console.log('授权手机号成功', phoneNumber) // 处理手机号授权成功后的逻辑 }, onPhoneAuthCancel() { console.log('取消授权') // 处理取消授权的逻辑 } } } </script> ``` 2. 在 `components` 目录下新建 `phone-auth` 组件 ```html <template> <view class="phone-auth" v-if="visible"> <view class="phone-auth__mask"></view> <view class="phone-auth__dialog"> <view class="phone-auth__title">手机号授权</view> <view class="phone-auth__content"> <button class="phone-auth__btn" open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber"> 授权手机号 </button> <button class="phone-auth__btn phone-auth__btn--cancel" @click="onCancel">取消</button> </view> </view> </view> </template> <script> export default { props: { visible: { type: Boolean, default: false } }, methods: { onGetPhoneNumber(e) { if (e.mp.detail.errMsg === 'getPhoneNumber:ok') { const encryptedData = e.mp.detail.encryptedData const iv = e.mp.detail.iv uni.request({ url: 'https://your-api.com/getPhoneNumber', method: 'POST', data: { encryptedData, iv }, success: res => { if (res.statusCode === 200) { console.log('授权成功', res.data.phoneNumber) this.$emit('success', res.data.phoneNumber) } else { console.error('授权失败', res) } }, fail: err => { console.error('授权失败', err) } }) } else { console.error('授权失败', e) } }, onCancel() { this.$emit('cancel') } } } </script> <style scoped> .phone-auth { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 999; } .phone-auth__mask { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); } .phone-auth__dialog { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 80%; max-width: 320rpx; background-color: #fff; border-radius: 8rpx; overflow: hidden; } .phone-auth__title { font-size: 32rpx; color: #333; text-align: center; padding: 32rpx 0; } .phone-auth__content { display: flex; flex-direction: column; align-items: center; justify-content: center; } .phone-auth__btn { width: 100%; height: 96rpx; font-size: 32rpx; color: #fff; background-color: #ff5040; border-radius: 48rpx; margin-bottom: 32rpx; } .phone-auth__btn--cancel { background-color: #999; } </style> ``` 3. 在 `your-api.com/getPhoneNumber` 接口中解密手机号码 ```php <?php // 解密手机号码 function decryptPhone($encryptedData, $iv, $sessionKey) { $aesKey = base64_decode($sessionKey); $aesIV = base64_decode($iv); $aesCipher = base64_decode($encryptedData); $result = openssl_decrypt($aesCipher, 'AES-128-CBC', $aesKey, OPENSSL_RAW_DATA, $aesIV); $data = json_decode($result, true); return $data['phoneNumber']; } // 获取小程序会话密钥 function getSessionKey($appId, $appSecret, $code) { $url = "https://developer.toutiao.com/api/apps/jscode2session?appid={$appId}&secret={$appSecret}&code={$code}"; $result = file_get_contents($url); $data = json_decode($result, true); return $data['session_key']; } // 获取加密数据和向量 $encryptedData = $_POST['encryptedData']; $iv = $_POST['iv']; // 获取小程序会话密钥 $appId = 'your_app_id'; $appSecret = 'your_app_secret'; $code = $_POST['code']; $sessionKey = getSessionKey($appId, $appSecret, $code); // 解密手机号码 $phoneNumber = decryptPhone($encryptedData, $iv, $sessionKey); // 返回解密后的手机号码 header('Content-Type: application/json'); echo json_encode([ 'phoneNumber' => $phoneNumber ]); ``` 注意,上述代码中的 `$appId` 和 `$appSecret` 分别是您在今日头条开发平台创建小程序应用后所分配的应用ID和应用密钥。您还需要将该文件上传到您的Web服务器上,并将接口地址替换为您实际上线的地址。 以上就是使用uniapp开发抖音小程序授权获取手机号的完整代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值