关于2.21.2 getPhoneNumber安全升级后的完美兼容措施
背景:从基础库 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解密失败");
}
}