Google令牌在前端和node端的使用

362 阅读3分钟

背景

Google令牌,其实不局限于google令牌,其他的很多手机令牌背后的逻辑都是差不多的,毕竟密钥和令牌计算逻辑已经开源了。就不赘述了

实现逻辑

当前令牌 = fn (密钥, 当前时间), 也就是当前令牌的六位数字只与密钥和当前时间有关系。 密钥和令牌生成的算法已经开源了。也就意味着:

  1. 只要拿到密钥,就可以计算出当前的令牌。听着有点不安全,但是吧,密钥都泄露了,那还谈算法的安全不安全就没意义了。
  2. 因为只需要密钥和时间,所以内网环境下离线使用也是完全可以的,只是要确保内外网时间一致。
  3. 算法都是开源的,也就意味着你不用google-auth-library来做,用其他的封装好的npm包生成的密钥也是可以用手机上的谷歌令牌软件识别。(不严谨,意思是这么个意思)

实现

这里我用otplib来演示一下,如果想用google-auth-library也可,但是吧,就是后者在配置上相对麻烦一丢丢。

生成密钥

不多赘述,直接上代码。

import { authenticator } from 'otplib';
const secret = authenticator.generateSecret();

完了?额,确实完了,就一行代码。
核心就是调用的generateSecret方法来生成一个密钥。这个密钥有两个作用:

  1. 用来让手机上的谷歌令牌软件识别进行绑定。
  2. 当输入令牌后,令牌的校验。

令牌的绑定

通常会采用生成一个二维码的方式来做谷歌令牌的绑定。

// 生成google手机令牌可以识别的二维码URI
const googleKeyUri = authenticator.keyuri('当前用户名字''产品名字',secret);
// 然后直接渲染就好,这里使用的qrcode.react,生成一个二维码,vue或者在nodejs参考其他的二维码生成方式。
<QRCodeCanvas value={googleKeyUri} />

用户使用手机扫描二维码,令牌就成功绑定上了。

令牌的校验

不多赘述,直接上代码。

const { authenticator } = require('otplib');
const check = (六位令牌码) => authenticator.check(六位令牌码, secret);

调用authenticator的check方法即可在服务端进行校验,将手机令牌的六位令牌码和先前的密钥作为参数即可。

值得注意的地方

这里只是写了核心的代码,密钥和用户的服务端存储,二维码的展示方式,是否绑定成功的验证都没有写,具体可以根据实际需求扩展。

  1. 在服务端生成密钥二维码再给前端展示也是可以的。
  2. 要做的完善一点的话,我们在第一次绑定上的时候需要进行是否绑定成功的确认,难免会有一些未知原因,服务器没存上。

写在最后的话

动态令牌在当下的互联网发展中是非常常见的,其内部实现逻辑TOTP (Time-based One-Time Password)也是现在国内主流的,具体的密码散列函数有兴趣的小伙伴可以去查一查。