关于2.21.2 getPhoneNumber安全升级后的完美兼容措施
发布于 2 年前 作者 leimo 4564 次浏览 来自 分享

背景:从基础库 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](/user/param) string $encryptedData
 * [@param](/user/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解密失败");
    }
}
回到顶部