微信小程序手机号快速验证授权失败?
一、前言
应用场景
授权获取微信绑定手机号。
使用方法
目前该项能力为微信收费能力,文章后续讲解了微信目前提供的2种实现方案,另整理了一下常见的授权问题。
二、微信能力
2.1 前提条件
- 要用户主动触发才能发起手机号快速验证, 需用 button 组件的点击来触发
- 满足验证额度;
- 1000次体验额度 = 正式版+体验版+开发版;
- 自2023年8月28日起,手机号快速验证组件执行付费使用。标准单价为:调用成功0.03元/次
- 服务器域名已授权在微信服务。
设置路径: 开发 → 开发管理 → 开发设置 → 服务器域名 (配置)
2.2 实现方案
2种方案基本流程
① 前端调用获取微信服务的数据
② 前端将必要数据传给服务端做记录
③ 服务端调用openAPI接口获取手机号,必要参数依赖②
方案一: 2.21.2之前的老方案
方案需要的code是wx.login的获取的code
步骤1:获取手机号;前端通过用户主动触发,回调获得加密数据
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}></button>
// 方式一:原生
Page({
getPhoneNumber (e) {
console.log(e.detail.errMsg)
console.log(e.detail.iv) // 加密算法初始向量
console.log(e.detail.encryptedData) // 加密数据
}
})
// 方式二:自定义方法
const handleGetPhoneNumber = (e) => {
const { iv, encryptedData , cloudID } = e?.detail || {};
console.log(e?.detail);
}
步骤2:登录,获取手机解密必须的session_key;
① 前端wx.login()登录获取code传给服务端
② 调用openAPI登录接口获取session_key
// ① 触发登录 wx.login()
wx.login({
success (res) {
if (res.code) {
//发起网络请求
wx.request({
url: 'https://example.com/api/path/to/put/logincode',
data: {
code: res.code
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
// ② 调用OpenAPI jscode2session
// GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
GET https://api.weixin.qq.com/sns/jscode2session
Request
{
appid,
secret, // 小程序 appSecret
js_code, // ① wx.login()中code
grant_type // authorization_code
}
Response
{
session_key, // 目标数据
unionid,
openid,
errmsg,
errcode
}
步骤3:解密手机号;服务端依据解密规则获取开发数据;(2种方式 服务端开发或云开发)
方式一:服务端开发 ① 校验签名 ② 解密开放数据
① 【签名】 调用接口(如 wx.getUserInfo)获取数据时,接口会同时返回 rawData、signature,其中 signature = sha1( rawData + session_key )
② 【解密】 将 signature、rawData 发送到开发者服务器进行校验。服务器利用用户对应的 session_key 使用相同的算法计算出签名 signature2 ,比对 signature 与 signature2 即可校验数据的完整性。
注意session_key的有效性,有效期或重新登录都有影响
方式二:云调用 ① 获取cloudId ② 调用云函数 具体详见解密规则
方案二:2.21.2 之后新方案
方案获取的code是前端获取手机号api的code,带着accessToken去调用最新的api接口去获取手机号,无需解密。
步骤1:获取动态令牌;前端通过用户主动触发,回调获得令牌
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
Page({
getPhoneNumber (e) {
console.log(e.detail.code) // 【动态令牌】与方案一的差异
console.log(e.detail.errMsg) // 回调信息(成功失败都会返回)
console.log(e.detail.errno) // 错误码(失败时返回)
}
})
步骤2:获取手机号;服务端通过通过动态令牌换取用户手机号。使用方法详情 phonenumber.getPhoneNumber
POST https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=ACCESS_TOKEN
Response { errorCode, errorMsg, phone_info }
phone_info {
phoneNumber: '+8613208021234', // 国内外带区号手机号
purePhoneNumber: '13208021234', // 不带区号手机号
countryCode: '86' // 区号
watermark: { // 水印
timestamp: 123455, // 获取手机号的时间戳
appid: 'xxxxxx', // 小程序appid
}
}