背景
Google令牌,其實不侷限於google令牌,其他的很多手機令牌背後的邏輯都是差不多的,畢竟金鑰和令牌計算邏輯已經開源了。就不贅述了
實現邏輯
當前令牌 = fn (金鑰, 當前時間), 也就是當前令牌的六位數字只與金鑰和當前時間有關係。 金鑰和令牌生成的演算法已經開源了。也就意味著:
只要拿到金鑰,就可以計算出當前的令牌。聽著有點不安全,但是吧,金鑰都洩露了,那還談演算法的安全不安全就沒意義了。
因為只需要金鑰和時間,所以內網環境下離線使用也是完全可以的,只是要確保內外網時間一致。
演算法都是開源的,也就意味著你不用google-auth-library來做,用其他的封裝好的npm包生成的金鑰也是可以用手機上的谷歌令牌軟體識別。(不嚴謹,意思是這麼個意思)
實現
這裏我用otplib來演示一下,如果想用google-auth-library也可,但是吧,就是後者在配置上相對麻煩一丟丟。
生成金鑰
不多贅述,直接上程式碼。
import { authenticator } from 'otplib'; const secret = authenticator.generateSecret();
完了?額,確實完了,就一行程式碼。
核心就是呼叫的generateSecret方法來生成一個金鑰。這個金鑰有兩個作用:
用來讓手機上的谷歌令牌軟體識別進行繫結。
當輸入令牌後,令牌的校驗。
令牌的繫結
通常會採用生成一個二維碼的方式來做谷歌令牌的繫結。
// 生成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方法即可在服務端進行校驗,將手機令牌的六位令牌碼和先前的金鑰作為引數即可。
值得注意的地方
這裏只是寫了核心的程式碼,金鑰和使用者的服務端儲存,二維碼的展示方式,是否繫結成功的驗證都沒有寫,具體可以根據實際需求擴充套件。
在服務端生成金鑰二維碼再給前端展示也是可以的。
要做的完善一點的話,我們在第一次繫結上的時候需要進行是否繫結成功的確認,難免會有一些未知原因,伺服器沒存上。
寫在最後的話
動態令牌在當下的網際網路發展中是非常常見的,其內部實現邏輯TOTP (Time-based One-Time Password)也是現在的主流,具體的密碼雜湊函式有興趣的小夥伴可以去查一查。