直接上代码,先看下优化前的代码
<button
class="button"
open-type="getPhoneNumber"
@getphonenumber="getPhoneNumber"
>
一键登录
</button>
function promisify<type>(method, options?): Promise<type> {
return new Promise((resolve, reject) => {
// 将options对象赋值 然后再传给下面调用的方法中
options = options || {};
options.success = resolve;
options.fail = reject;
uni[method](options);
});
}
// 一键获取手机号登录
const getPhoneNumber = async(e) => {
const {
encryptedData,
iv,
errMsg,
} = e.detail;
if (errMsg == 'getPhoneNumber:fail:user deny'
|| errMsg == 'getPhoneNumber:fail user deny'
|| errMsg == 'getPhoneNumber:fail:user cancel'
) {
return ‘refuse’; // 用户拒绝授权
}
if (errMsg === 'getPhoneNumber:ok') {
try {
const { code } = await promisify<{code: string}>('login');
await requestLogin({
iv,
encryptedData,
js_code: code,
});
await getUserInfo();
return 'success';// 登录成功
} catch (err) {
console.log('登录失败', err);
return 'fail'; // 登录失败
}
}
};
部署后发现每天早晨第一次点击“一键登录按钮”的时候会出现登录失败的情况,经过研究发现
复现步骤:多次点击”一键登录“按钮但是授权弹窗中点击“不允许”按钮,最后再点击“手机号”授权发起请求
调研
在getPhoneNumber回调中调用 wx.login 登录,可能会刷新登录态。此时服务器使用wx.login得到的code 换取的 sessionKey 不是加密手机号时使用的 sessionKey,导致解密失败。建议开发者提前进行 login;或者在回调中先使用 checkSession 进行登录态检查,避免 login 刷新登录态。
优化后的代码
html增加点击事件,在用户在弹窗中授予手机号权限之前先执行点击事件获取微信登录code
<button
class="button"
open-type="getPhoneNumber"
@getphonenumber="getPhoneNumber"
@click="getWxLoginCode"
>
一键登录
</button>
function promisify<type>(method, options?): Promise<type> {
return new Promise((resolve, reject) => {
// 将options对象赋值 然后再传给下面调用的方法中
options = options || {};
options.success = resolve;
options.fail = reject;
uni[method](options);
});
}
const js_code = ref("");
// 通过微信login方法获取code
const getWxLoginCode = async() => {
console.log('getWxLoginCode');
try {
const {code} = await promisify<{code: string}>('login');
js_code.value = code;
} catch (error) {
console.log('getWxLoginCode:', error);
}
};
// 使用 `checkSession` 进行登录态检查
const checkSession = () => promisify('checkSession').then(() => true).catch(() => false);
// 一键获取手机号登录
const getPhoneNumber = async(e) => {
const loginState = await checkSession();
console.log('loginState:', loginState);
if(!loginState) {
await getWxLoginCode();
}
const {
encryptedData,
iv,
errMsg,
} = e.detail;
if (errMsg == 'getPhoneNumber:fail:user deny'
|| errMsg == 'getPhoneNumber:fail user deny'
|| errMsg == 'getPhoneNumber:fail:user cancel'
) {
return ‘refuse’; // 用户拒绝授权
}
if (errMsg === 'getPhoneNumber:ok') {
try {
await requestLogin({
iv,
encryptedData,
js_code: js_code.value,
});
await getUserInfo();
return 'success';// 登录成功
} catch (err) {
console.log('登录失败', err);
return 'fail'; // 登录失败
}
}
};
现在获取微信登录code时机是早于获取电话号码的,当用code获取的解密信息去解密手机号加密信息iv、encryptedData时是可以解密的。
每次wx.login都会更新解密信息,并且解密信息会在微信服务器保存一段时间,要确保解密成功,一定要用获取加密信息之前wx.login时获取的解密信息进行解密。