一、之前的解密流程,会偶现“解密失败”,步骤如下:
1、点击 ‘getPhoneNumber’ 的按钮,弹出授权界面
2、调用 wx.checkSession 进行检查,success 的话就发送授权手机号解密接口;fail 的话就进行 wx.login 获取 code 后请求后端获取 openid/sessionKey,并将两个值缓存到本地,然后再进行手机号解密。
二、粗暴方式解密流程,会偶现“解密失败”,步骤如下:
1、点击 ‘getPhoneNumber’ 的按钮,弹出授权界面
2、调用 wx.login 获取 code 后请求后端获取 openid/sessionKey,然后进行手机号解密
探讨微信解密机制(个人理解,如有不对,请指出哟),如下:
1、点击 ‘getPhoneNumber’ 的按钮,弹出授权界面时,在微信后台会生成一个加密的 ‘encryptedData’ 和拉取用于解密的 ‘sessionKey-0(-0为假想标识符)’,sessionKey 是 wx.login 解密之后生成的,在微信后台会存储。
2、按照如上错误的步骤,进行 wx.login 获取 code 再获取 sessionKey-1,由于 wx.login 会刷新微信后台的登录状态,此时获取的 sessionKey-1 和上一步中点击按钮在微信后台生成的 sessionKey-0 并不是同一个,于是解密失败了。
3、重点:必须保持操作前后的 sessionKey 都是同一个,如果 wx.login 刷新了后台的 sessionKey,而之前的操作还是原来的 sessionKey,则会失败。
必现方式一(解密失败),如下:
1、正常授权解密后,关闭小程序一段时间,测试的时候大概 30-40 分钟左右,后台 sessionKey 过期了
2、重新打开小程序走之前的步骤,出现“解密失败”,然后第二次进行授权解密时,又成功了
必现方式二(解密失败),如下:
1、清理缓存后,点击授权登录(此时后台的sessionKey为空,所以无论怎么做登录和检查,都会解密失败),弹出界面后调用 wx.login 进行登录获取 sessionKey
2、授权解密,失败
3、再次点击授权登录(此时会获取第一步中登录生成的 sessionKey,与未过期的sessionKey一致),则进行解密,成功。
解决方案,如下:
基于对上面机制的理解,wx.login 方式获取的 sessionKey 必须在唤起授权弹窗前进行,必须保证授权弹窗时获取的 sessionKey 和 本地未过期的sessionKey是同一个。
1、在 app.js 的 onLaunch 中,先进行 wx.checkSession。success,则进行后续代码执行;如果 fail,则进行 wx.login 重新获取 sessionKey,后端同学将 sessionKey 存储至数据库,openid 是唯一的,可以作为主键。此时,会先于任何操作之前生成一个 sessionKey。
2、唤起授权界面,点击“允许”后,将 openid+iv+encryptedData 传给后端进行解密。
代码如下(IDE复制后没发改样式,const 等变量可能看不清,可以复制到自己的编辑器中查看哈):
然后在 onLaunch 中调用 onLogin.checkSession 进行前置 session 检查和获取
export const onLogin = {
// 检查 session 是否有效
checkSession(cb = () => {}) {
const _this = this;
// 检查登录态是否可用
wx.checkSession({
success () {
console.log('session success');
// session_key 未过期,并且在本生命周期一直有效
const { openid, session_key } = wx.getStorageSync('session');
cb(openid, session_key);
},
// 登录态失效了
fail () {
console.log('session fail');
_this._wxLogin((openid, session_key) => {
cb(openid, session_key);
});
}
});
},
// 微信获取 code 进行解密
_wxLogin(cb = () => {}) {
// 将 js_code 发送给后端获取 openId 和 sessionKey,并进行缓存
wx.showLoading({ mask: true });
wx.login({
success: ({ code }) => {
// 将 js_code 发送给后端获取 openId 和 sessionKey,并进行缓存
request({
url: `/wx/open/getSessionKey.json?code=${code}&clientIdentity=${CONFIG.clientIdentity}`,
onSuccess: ({ openid, session_key }) => {
wx.setStorageSync('session', { openid, session_key });
cb(openid, session_key);
},
complete: () => {
wx.hideLoading();
}
})
}
});
},
}