面试官:你说一说扫码登录的原理
我:呃,打开网页,网页上显示一个二维码,用app扫描它,然后就可以登录了。
面试官:讲得很好,后续有消息我在通知你
扫码登录是网站常用的一个功能,并且也是面试的高频考点,虽然经常使用,但是可能有些童鞋对它的实现过程和原理并不是很清楚,导致错失百万年薪的offer。今天趁着周末无聊,实现一个简单的扫码登录。
初始化一个uni-app项目,扫码登录肯定需要使用到app或者微信小程序。用uni-app随便先搞一个简单的app
先下载一个HBuilderX (www.dcloud.io/hbuilderx.h…)
随便初始化一个项目
扫码登陆,肯定是需要已经登录用的app来进行扫码,所以随便写两行代码实现一个简单的登录页面
一个账号框、一个密码框、一个登录按钮
使用koa2,随便初始化一个后端项目
npm install koa-generator -g
koa2 (xxxx)项目名
cd xxxx
npm install
npm install koa2-cors
然后在app.js中加入以下代码
app.use(cors({
origin:function (ctx) {
if(ctx.url === '/string'){
return "*";
}
return '*';
},
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
maxAge: 5,
credentials: true,
allowMethods: ['GET', 'POST', 'DELETE'],
allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}));
每次更改了node项目以后,因为没有使用热更新, 所以需要重新npm start一下,
为了简单起见,随便定义一个用户信息,实现一个登录接口
输入账号密码以后,点击登录,然后在uni-app中调用登录接口
uni.request({
url: 'http://xxx.xxx.xxx.xxx:3000/login', // 注意此处的ip不能用localhost或者127.0.0.1 需要使用ipconfig 拿到的真实的电脑ip,否则在手机上无法调用接口
method: 'POST',
data: {
userName: this.userName, // 输入的用户名
password: this.password // 输入的密码
},
success: ({data}) => {
if(data.code === 1) {
this.isLogin = true; // 表示已经登录
this.token = data.token // 记录返回的token信息
}
},
fail: (err) => {
console.log(err)
}
});
这里的目的,是为了在手机端口进行登录,登录了以后需要返回token信息,然后记录下来
然后实现扫码功能,这里uni-app中已经内置了扫码功能,我们直接调用即可
uni.scanCode({
success: (res) => {
// res.result 拿到扫描的结果
// 扫码成功需要在此处发起请求
}
});
需要注意的使用,在pc端点击扫码按钮,是无法唤起扫码的,所以需要连接手机,使用数据线连接手机和电脑,然后打开usB调试即可
有问题可以参考:hx.dcloud.net.cn/Tutorial/Ap…
点击扫码按钮,可以看到已经能够唤起扫码功能了
然后现在我们需要随便准备一张二维码来扫描,在刚刚的koa后端项目中安装一个qr-image
npm install qr-image
然后引入,并且新定义一个接口create_qrcode,随便生成一个random_img_id,然后生成对应的二维码,在把图片返回到前端(PC端)
现在需要有一个pc端的网站,来显示二维码图片,为了简单,我们直接新建一个html文件。 一行代码即可显示二维码
<img src="http://localhost:3000/create_qrcode" />
用微信扫描这个张二维码,可以看到二维码对应的10位随机数字信息
在实际应用中,扫描了二维码以后,可以看到二维码上面会显示已扫描,那么我们在扫描以后,需要调用一个接口来修改二维码状态,并且获得从后台返回的临时令牌
现在来实现扫描以后的逻辑
uni.scanCode({
success: (res) => {
ni.request({
url: 'http://xxx:xxx:xxx:xxx:3000/change_img_status',
method: 'POST',
data: {
code: res.result, // 将二维码扫描结果发送到后台
},
success: ({data}) => {
this.isScanStaus = true; // 表示已经扫描了二维码
this.random_token = data.random_token; // 记录临时令牌
}
})
}
});
那么pc端是如何知道二维码已经被扫描了呢?其实很简单,我们可以通过websocket或者轮询的方式来处理,为了简单起见,我们使用轮询的方式来查询二维码的状态,判断是否扫描
先需要定义一个接口,来查询二维码的状态
在pc端对应的html文件中编写一下简单的代码
然后引入vue
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
初始状态是显示未登录,获取二维码按钮
一旦点击了获取二维码按钮以后,轮询的去查询二维码状态
当app扫码以后就会显示已扫码
然后我们需要实现app扫码以后,会弹出确认登录,点击确认登录,整个扫码过程才算结束
先实现确认登录接口,校验app的token信息和临时令牌信息是否正确,如果正确,那么修改扫码状态即可
在uni-app中调用接口,参数为token和临时令牌
点击确定按钮以后,pc端的轮询接口中就会返回token信息,然后就能获取到哪个用户扫码,并停止轮询
至此整个扫码登录过程结束,当然实际应用中肯定是要复杂得多的。
总结一下扫码登录的整个流程:
-
pc端未登录状态下访问服务器,服务器查看是未登录状态,返回一个二维码,二维码中包含了特定的信息
-
pc端就会一直发送轮询请求(或者通过websocket)来请求是否扫码
-
手机等(登录过账号的)扫描二维码,会调用相关的接口识别二维码信息,并且会发送token到服务器,服务器拿到token以后,会将二维码状态变更为已扫码,所以pc端就会显示已扫码
-
然后服务端校验token和二维码信息,然后返回一个临时令牌,给移动端
-
移动端弹出是否确认登录提示,点击登录
-
将临时令牌返回到服务器,服务器校验临时令牌(为了防止扫码手机和登录手机不一致),校验通过以后,从token中拿出信息,并同步到pc端
-
pc端登录成功