小程序登录授权+获取手机号踩坑记
最近在做toC的小程序, 之前做过的东西又重新捡了起来。 但是发现之前踩过的一些坑,又被自己重新踩了一遍。
脑子真的是记不住啊~ 忙里抽闲赶紧做个笔记。
重点笔记:获取微信用户绑定的手机号,需先调用wx.login接口。
原理:小程序获取到的手机号信息为微信服务器加密后的信息。 微信服务器会根据wx.login颁发的临时code对应的sessionKey来加密手机号信息。 在开发者服务器使用 code 换取 sessionKey , 比对换取的sessionKey与加密信息时使用的sessionKey一致才可解密成功。
注意:服务器使用 code 换取的 sessionKey 不是加密时使用的 sessionKey,导致解密失败。建议开发者提前进行
login。
一、 登录授权需求
因业务限制,用户登入小程序前需先授权手机号才能进入小程序。
前端在App.js入口文件中读取本地存储, 判断是否有手机号,有则直接刷新用户信息登入,无则需走登录授权流程登入。
二、 19年开发的公司内部小程序,登录授权设计。
后台设计两个接口, 登录注册接口、更新用户信息接口。
登录注册接口逻辑:
1、根据入参code,调用微信 auth.code2Session 接口换取openId、session_key。
2、换取成功,查询入参openId在用户表中是否存在,存在则更新session_key, 不存在则创建用户并存储openId、session_key。 处理后将openId返给前端。
前端调用:
登录页onShow生命周期中,调用该接口,并将返回数据在页面state记录。
onShow: function () {
let that = this;
// 判断是否缓存手机号
that.data.purePhoneNumber = wx.getStorageSync("purePhoneNumber");
if (that.data.purePhoneNumber == '') {
wx.login({
success(res) {
WXrequest.post({
url: '/code2Session',
data: {
'jsCode': res.code
}
}).then(res => {
wx.setStorageSync('openid', res.data.openid);
that.data.openid = res.data.openid;
});
}
});
} else {
wx.showLoading({
title: '登录中' // 数据请求前loading
})
wx.switchTab({
url: '../mine/index'
})
}
}
更新用户信息接口逻辑:
1、根据入参openId去用户表中查询session_key, 并结合入参encryptedData、iv解密获取手机号。
2、解密到手机号后,更新用户信息并将用户信息返给前端。
前端调用:
用户主动触发登录按钮, 获取手机号后调用。
getPhoneNumber: function (e) {
let that = this;
if (e.detail.errMsg == 'getPhoneNumber:ok') {
WXrequest.post({
url: '/getWXUserPhone',
data: {
'encryptedData': e.detail.encryptedData,
'openid': that.data.openid,
'iv': e.detail.iv,
}
}).then(res => {
// 存用户手机号及用户信息
wx.setStorageSync('purePhoneNumber', res.data.purePhoneNumber);
wx.setStorageSync('userInfo', res.data);
// 跳转首页
wx.showLoading({
title: '登录中'
})
setTimeout(function () {
wx.switchTab({
url: '../mine/index'
})
}, 1000)
})
}
}
注:code有效期为五分钟,在登录页onShow生命周期中获取code, 如果用户打开页面5分钟后再授权手机号,则会解密失败。需要做优化处理。
三、 最近开发的toC小程序登录授权设计。
后台同事将小程序登录+获取手机号设计为一个接口,叫登录授权接口。
接口逻辑:
1、根据入参code先去调用 auth.code2Session 接口换取openId、session_key。
2、根据 appId、入参encryptedData、上一步换取的session_key,进行数据解密,获取手机号。
3、查询openId在用户表中是否存在,进行逻辑处理。
存在,判断该用户手机号与解析出来的手机号是否一致,一致接口返回用户信息;不一致,更新手机号,将之前的手机号做历史记录。
不存在, 直接创建用户,返回用户信息。
前端调用:
因考虑到code,有效期为五分钟。 在登录页onShow生命周期中获取code, 无法保证用户一定会在五分钟内授权手机号。
所以在获取手机号成功后再调用wx.login()获取code, 再去调用登录授权接口。
问题:
先获取手机号再调用wx.login(), 造成后台解析手机号失败,报错:session_key失效。
根据以往经验,直接开始撸代码了,时间太久忘了一些注意事项。报错后才重新读了一遍文档,文档中明确提示:获取微信用户绑定的手机号,需先调用wx.login接口。
注:阅读下面文档, 了解微信对开放数据校验与解密, 对获取手机号之前为什么要调用wx.login接口有更深刻的印象。
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html
解决方案:
登录页onShow生命周期中每隔几分钟,重新刷一下登录态。 在页面state记录状态, 获取手机号成功后一起传给后台。
componentDidShow() {
// 隐藏房子
Taro.hideHomeButton();
// code 用户登录凭证(有效期五分钟), 停留在当前页面每隔两分钟,重新刷新登陆态,否则后台解析session_key会失效
Taro.login({
success: (res) => {
this.setState({
code: res.code,
});
},
});
this.timer = setInterval(() => {
Taro.login({
success: (res) => {
this.setState({
code: res.code,
});
},
});
}, 60000 * 2);
}
// 获取手机号
getPhoneNumber(e) {
if (e.detail.errMsg.indexOf("getPhoneNumber:fail") != -1) {
if (e.detail.errMsg.indexOf("user cancel") != -1) {
toast("请不要重复点击、以免取消微信授权");
} else {
toast("允许授权将获得更好的服务");
}
} else {
this.setState({
loading: true,
});
Taro.request({
url: `${config.baseUrl}/user`,
method: "POST",
header: { "Content-Type": "application/json" },
data: {
code: this.state.code,
iv: e.detail.iv,
encryptedData: e.detail.encryptedData,
},
success: (res) => {
const redData = res.data.data || {};
if (res.data.code != 0) {
toast(res.data.msg);
} else {
Taro.setStorageSync(`${config.env}openId`, redData.openId);
Taro.setStorageSync(`${config.env}userId`, redData.userId);
Taro.setStorageSync(`${config.env}phone`, redData.phone);
this.props.dispatch({
type: "User/setUser",
payload: {
userInfo: redData,
},
});
this.setState({
loading: false,
});
}
},
fail: (err) => {
this.setState({
loading: false,
});
toast(err);
},
});
}
}
// DOM
<Button
type="primary"
disabled={this.state.loading}
loading={this.state.loading}
className={styles.phone}
openType="getPhoneNumber"
onGetPhoneNumber={(e) => this.getPhoneNumber(e)}
>
{this.state.loading ? "登录中" : "授权手机号"}
</Button>
四、进一步了解微信登录授权机制原理。
踩坑后重新研究了OAuth 2.0 安全协议, 小程序登录授权、开放数据校验与解密等流程及背后原理。
抽时间整理在后面的笔记中...
转载自:https://juejin.cn/post/7008573259876663333