评论

关于2.21.2 getPhoneNumber安全升级后的完美兼容措施

从基础库 2.21.2 开始,对获取手机号的接口进行了安全升级。 过渡阶段,为避免新老版本出现不能获取手机号的情况,可以如文中进行兼容处理。

背景:从基础库 2.21.2 开始,对获取手机号的接口进行了安全升级。

问题:

1、如果直接采用code换手机号,在没有更新基础库的设备上肯定是undefined。

2、PC端上不支持cloudID云函数解密。

3、其他不可告人的原因。


话不多说,直接上代码:

index.wxml

<button open-type="getPhoneNumber" bindgetphonenumber="onPhoneNumberGet">{{phone ? phone : "请输入手机号码"}}</button>


index.js

onPhoneNumberGet: function (e) {
  utils.getPhoneNumber(e, mobile => {
    console.debug('mobile', mobile)
    //do something
  })
}


云函数openapi

const cloud = require('wx-server-sdk')
cloud.init({
    env: cloud.DYNAMIC_CURRENT_ENV
})

exports.main = async (event, context) => {
    switch (event.action) {
        case 'code2PhoneNumber': {//云函数code换取手机号码
            return code2PhoneNumber(event)
        }
        default: {//cloudID解密
            return event
        }
    }
}

async function code2PhoneNumber(event) {//记得在config.json permissions.openapi 下添加 phonenumber.getPhoneNumber授权
    const res = await cloud.openapi.phonenumber.getPhoneNumber({
        code: event.code
    })
    return res
}


utils.js部分

...
const getPhoneNumber = function (e, callback) {
    if (!e || !e.detail || e.detail.errMsg != 'getPhoneNumber:ok') {
        toast('请允许我们获取你的手机号')
        return
    }
    if (e.detail.hasOwnProperty('code') && e.detail.code) {//基础库>2.21.2
        wx.cloud.callFunction({
            name: 'openapi',
            data: {
                action: 'code2PhoneNumber',
                code: e.detail.code
            }
        }).then(res => {
            console.debug('[code2PhoneNumber] 调用成功:', res)
            if (!res || !res.result || !res.result.phoneInfo) {
                toast('获取手机号失败')
            } else if (res.result.hasOwnProperty('errCode') && res.result.errCode != 0) {
                toast(res.result.errMsg)
            } else if (callback && typeof callback === 'function') {
                callback(res.result.phoneInfo.phoneNumber)
            }
        }).catch(err => {
            console.debug('[code2PhoneNumber] 调用失败:', err)
        })
    } else if (e.detail.hasOwnProperty('cloudID') && e.detail.cloudID) {//开通云开发且基础库>2.8.0 PC版不支持
        wx.cloud.callFunction({
            name: 'openapi',
            data: {
                action: 'getPhomeNumber',
                userInfo: wx.cloud.CloudID(e.detail.cloudID)
            }
        }).then(res => {
            console.debug('[getphonenumber] 调用成功:', res)
            if (!res || !res.result || !res.result.userInfo) {
                toast('获取手机号失败')
            } else if (res.result.userInfo.hasOwnProperty('errCode')) {
                toast(res.result.userInfo.errMsg)
            } else if (callback && typeof callback === 'function') {
                callback(res.result.userInfo.data.phoneNumber)
            }
        }).catch(err => {
            console.debug('[getphonenumber] 调用失败:', err)
        })
    } else if (e.detail.hasOwnProperty('encryptedData') && e.detail.encryptedData) {//非上述条件可自行解密
        post('/profile/decrypted', {
            data: {
                encryptedData: e.detail.encryptedData,
                iv: e.detail.iv
            },
            success: res => {
                if (callback && typeof callback === 'function') {
                    callback(res.phoneNumber)
                }
            }
        })
    } else {
        toast('当前版本不支持该功能')
    }
}
...


接下来就是后端php自行解密接口

/**
 * 微信小程序加密数据解密/profile/decrypted API
 * @param string $encryptedData
 * @param string $iv
 */
public function decrypted()
{
    //$this->user["session_key"] 在用code2session登录的时候已经跟当前用户建立了对应关系 客户端做好checkSession有效验证即可
    $encryptedData = $this->input->post("encryptedData");
    $iv = $this->input->post("iv");
    if (!$encryptedData) ajax_error("源数据错误");
    if (!isset($this->user["session_key"]) || strlen($this->user["session_key"]) != 24) ajax_error("session_key 已过期");
    if (strlen($iv) != 24) ajax_error("iv参数错误");
    try {
        $aesKey = base64_decode($this->user["session_key"]);
        $aesIV = base64_decode($iv);
        $aesCipher = base64_decode($encryptedData);
        $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
        $data = json_decode($result, true);
        if (!$data || $data["watermark"]["appid"] != config_item("appid")) ajax_error("数据解密失败");
        ajax($data);
    } catch (Exception $e) {
        ajax_error("base64解密失败");
    }
}
最后一次编辑于  2022-03-07  
点赞 1
收藏
评论

4 个评论

  • @微信用户
    @微信用户
    2022-11-15

    客户跑到公司说小程序有用户不能登录,一看,哦豁,没code有个cloudID,版本库一换,就有code...,文档里面没有看到说明。。。

    2022-11-15
    赞同 1
    回复 1
    • @微信用户
      @微信用户
      2022-11-15
      说实话,这个社区登录,我明明选择了另一个头像昵称登录,但是还是显示我微信的头像昵称,只许州官放火,不许百姓点灯是吧
      2022-11-15
      回复
  • 心之所向
    心之所向
    2022-07-14

    真恶心,这个新版的接口是个辣鸡

    2022-07-14
    赞同
    回复
  • ElPsyCongroo
    ElPsyCongroo
    2022-05-26

    真恶心 , 随随便便修改接口

    2022-05-26
    赞同
    回复
  • 八九
    八九
    2022-03-07

    已阅

    2022-03-07
    赞同
    回复 1
登录 后发表内容