周末好时光,花十分钟卷一个扫码登录

9,177 阅读5分钟

面试官:你说一说扫码登录的原理

我:呃,打开网页,网页上显示一个二维码,用app扫描它,然后就可以登录了。

面试官:讲得很好,后续有消息我在通知你

扫码登录是网站常用的一个功能,并且也是面试的高频考点,虽然经常使用,但是可能有些童鞋对它的实现过程和原理并不是很清楚,导致错失百万年薪的offer。今天趁着周末无聊,实现一个简单的扫码登录。

初始化一个uni-app项目,扫码登录肯定需要使用到app或者微信小程序。用uni-app随便先搞一个简单的app

先下载一个HBuilderX (www.dcloud.io/hbuilderx.h…)

随便初始化一个项目

image.png

扫码登陆,肯定是需要已经登录用的app来进行扫码,所以随便写两行代码实现一个简单的登录页面

image.png

一个账号框、一个密码框、一个登录按钮

使用koa2,随便初始化一个后端项目

npm install koa-generator -g
koa2 (xxxx)项目名
cd xxxx
npm install
npm install koa2-cors

然后在app.js中加入以下代码

image.png

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一下,

为了简单起见,随便定义一个用户信息,实现一个登录接口

image.png

输入账号密码以后,点击登录,然后在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)
    }
});

image.png

这里的目的,是为了在手机端口进行登录,登录了以后需要返回token信息,然后记录下来

然后实现扫码功能,这里uni-app中已经内置了扫码功能,我们直接调用即可

uni.scanCode({
    success: (res) => {
        // res.result 拿到扫描的结果
        // 扫码成功需要在此处发起请求
    }
});

需要注意的使用,在pc端点击扫码按钮,是无法唤起扫码的,所以需要连接手机,使用数据线连接手机和电脑,然后打开usB调试即可

image.png 有问题可以参考:hx.dcloud.net.cn/Tutorial/Ap…

点击扫码按钮,可以看到已经能够唤起扫码功能了

99d430d5f8245e226f295d1f4ba431d.jpg

然后现在我们需要随便准备一张二维码来扫描,在刚刚的koa后端项目中安装一个qr-image

npm install qr-image

然后引入,并且新定义一个接口create_qrcode,随便生成一个random_img_id,然后生成对应的二维码,在把图片返回到前端(PC端)

image.png

现在需要有一个pc端的网站,来显示二维码图片,为了简单,我们直接新建一个html文件。 一行代码即可显示二维码

<img src="http://localhost:3000/create_qrcode" />

image.png

用微信扫描这个张二维码,可以看到二维码对应的10位随机数字信息

在实际应用中,扫描了二维码以后,可以看到二维码上面会显示已扫描,那么我们在扫描以后,需要调用一个接口来修改二维码状态,并且获得从后台返回的临时令牌

image.png

现在来实现扫描以后的逻辑

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或者轮询的方式来处理,为了简单起见,我们使用轮询的方式来查询二维码的状态,判断是否扫描

先需要定义一个接口,来查询二维码的状态

image.png

在pc端对应的html文件中编写一下简单的代码 image.png

然后引入vue

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

image.png

初始状态是显示未登录,获取二维码按钮

image.png

一旦点击了获取二维码按钮以后,轮询的去查询二维码状态

image.png

当app扫码以后就会显示已扫码

image.png

然后我们需要实现app扫码以后,会弹出确认登录,点击确认登录,整个扫码过程才算结束

先实现确认登录接口,校验app的token信息和临时令牌信息是否正确,如果正确,那么修改扫码状态即可

image.png

在uni-app中调用接口,参数为token和临时令牌

image.png

点击确定按钮以后,pc端的轮询接口中就会返回token信息,然后就能获取到哪个用户扫码,并停止轮询 image.png

至此整个扫码登录过程结束,当然实际应用中肯定是要复杂得多的。

总结一下扫码登录的整个流程:

  1. pc端未登录状态下访问服务器,服务器查看是未登录状态,返回一个二维码,二维码中包含了特定的信息

  2. pc端就会一直发送轮询请求(或者通过websocket)来请求是否扫码

  3. 手机等(登录过账号的)扫描二维码,会调用相关的接口识别二维码信息,并且会发送token到服务器,服务器拿到token以后,会将二维码状态变更为已扫码,所以pc端就会显示已扫码

  4. 然后服务端校验token和二维码信息,然后返回一个临时令牌,给移动端

  5. 移动端弹出是否确认登录提示,点击登录

  6. 将临时令牌返回到服务器,服务器校验临时令牌(为了防止扫码手机和登录手机不一致),校验通过以后,从token中拿出信息,并同步到pc端

  7. pc端登录成功