登录原理
- 用户打开 Web 端网页,进入扫码登录的界面;
- 从 Web 端服务器获取二维码的图并获取其状态;
- Web 端服务器在生成二维码时,会生成一个 uuid 和二维码进行关联,并将 uuid 存入 db 记录中;
- 用户打开 APP 端,对着二维码进行扫码授权操作;
- APP 客户端从二维码中读取到 uuid,带着 APP 内的身份信息访问 APP 端服务器;
- APP 端服务器获取到用户的身份信息后,将用户 id 更新到 db 中对应 uuid 的记录中,此时 Web 服务器就能拿到对应的用户 id,之后生成登录身份信息返回给浏览器,即用户在 Web 端完成了登录;
基于以上分析,我们可以将扫码登录分为两个步骤:获取扫码状态和获取用户登录信息。
获取扫码状态的三种方案
- 长链接
- 优点:
- 减少资源浪费
- 比轮询响应速度快
- 缺点
- 占用服务端大量连接数
- 优点:
- 轮询
- 优点:
- 开发易维护
- 更快释放连接
- 缺点
- 产生大量无效访问
- 优点:
- 长轮询
- 优点
- 结合了长链接和轮询的优点削弱了缺点
- 缺点
- 开发起来更加复杂,相当于实现了两种方案
- 优点
目前主流方案是定时轮询,这是由于扫码登录本身也是低频操作,并不会造成很大量的请求,但优点又比较突出。
实现
onMounted 获取二维码信息
接口返回url
生成二维码【QRCode.toDataURL()生成二维码图片链接】
轮询二维码状态【调用轮询接口,已扫码确认,清除轮询,获取用户信息】
轮询
清除轮询
// 获取二维码信息
const getQRInfo = () => {
postV1QrInfo({ app_id: 3, source: "web" }).then((res) => {
console.log(res);
generateQRcode(res.data.login_url);
QRinfo.value = res.data;
checkQRcode();
timer = setInterval(() => {
checkQRcode();
}, 1000 * 11);
timeOut = setTimeout(() => {
clearCheck(true);
}, 1000 * res.data.timeout);
});
};
// 生成二维码
const generateQRcode = (url: string) => {
QRCode.toDataURL(url, { width: 280, height: 280, color: { dark: "#6697f1", light: "#fff" } })
.then((res: any) => {
// 生成的二维码链接
code.value = res;
})
.catch(() => {});
};
// 清除轮询
const clearCheck = (codeStatus: boolean) => {
isExpired.value = codeStatus;
clearInterval(timer);
clearTimeout(timeOut);
};
// 轮询二维码状态
const checkQRcode = () => {
postV1Check({ qr_code: QRinfo.value.qr_code, app_id: 3, source: "web" }).then((res) => {
console.log(res);
// 1-未扫码 2-已扫码确认
if (res.data.status === 2) {
clearCheck(false);
userInfoStore.setToken(res.data.jwt);
getUserInfo();
}
});
};