Golang實現(xiàn)基于時間的一次性密碼TOTP
上篇文章詳細講解了一次性密碼 OTP 相關的知識,基于時間的一次性密碼 TOTP 是 OTP 的一種實現(xiàn)方式。這種方法的優(yōu)點是不依賴網(wǎng)絡,因此即使在沒有網(wǎng)絡的情況下,用戶也可以生成密碼。所以這種方式被許多流行的網(wǎng)站使用到雙因子或多因子認證中,包括 Google、GitHub、Facebook 和 Salesforce 等等。
因為 TOTP 是標準化的協(xié)議并且被廣泛采用,所以有很多對應的移動應用或者 web 應用實現(xiàn),被稱為身份驗證器應用,例如 Google Authenticator、Microsoft Authenticator 等。Golang 也有很多優(yōu)秀的三方庫可以幫助我們快速實現(xiàn) TOTP 的服務端實現(xiàn),其中比較有代表性的是 pquerna/otp 庫,接下來就使用這個庫來演示一下 TOTP 的服務端實現(xiàn)流程。
為用戶生成 TOTP Key
用戶開啟雙因子認證時,為用戶生成 TOTP Key,用于生成 TOTP 密碼。將這個密碼保存在數(shù)據(jù)庫或者秘鑰管理系統(tǒng)中,生成 key 的關鍵代碼如下:
key, err := totp.Generate(totp.GenerateOpts{
Issuer: "Github",
AccountName: "user@example.com",
Period: 30,
Digits: otp.DigitsSix,
Algorithm: otp.AlgorithmSHA1,
})
這幾個參數(shù)的意思如下:
Issuer 意思是應用名稱,例如 Github。
AccountName 意思要給哪個用戶生成 key。
Period 意思是 TOTP 密碼的有效時間,也是不同 TOTP 密碼的生成時間間隔,一般為 30 秒。
Digits 意思是生成的密碼長度,一般為 6 位。
Algorithm,用于 HMAC 簽名的算法,默認是 SHA1。
把密鑰和密碼生成規(guī)則分享給用戶
通常是將秘鑰和密碼規(guī)則信息以二維碼的形式展示給用戶,用戶使用身份驗證器應用掃描二維碼保存相關信息并且生成密碼。二維碼中的內(nèi)容格式一般如下:
otpauth://totp/Github:user@example.com?algorithm=SHA1&digits=6&issuer=Github&period=30&secret=5RLOAFJOB6LRV7WOKFIMDZ5IESZ7L3JM
為用戶提供“恢復碼” Recovery Codes
生成“恢復碼” Recovery Codes (使用隨機生成的字符串即可)存儲到數(shù)據(jù)庫或者秘鑰管理系統(tǒng)中。當用戶不能訪問自己的 TOTP 設備(例如將 TOTP 應用中的 TOTP 秘鑰刪除了、將 TOTP 應用卸載了、手機丟失了等)時,就無法登錄自己的帳戶了。因為這種情況比較常見,所以很多網(wǎng)站都會給用戶提供“備份代碼”或“恢復代碼”,并且每個只能使用一次,可以臨時用來代替 TOTP 密碼。
校驗用戶輸入的 TOTP 密碼
用戶再次登錄后,觸發(fā)雙因子認證,要求用戶輸入 TOTP 密碼,服務端檢驗這個密碼。校驗的關鍵代碼如下:
// 驗證一次性密碼 isValid := totp.Validate(passcode, key.Secret())
模擬生成密鑰、校驗密碼的代碼
package main
import (
"fmt"
"time"
"github.com/pquerna/otp"
"github.com/pquerna/otp/totp"
)
func main() {
// 生成密鑰
key, err := totp.Generate(totp.GenerateOpts{
Issuer: "Github",
AccountName: "user@example.com",
Period: 30,
Digits: otp.DigitsSix,
Algorithm: otp.AlgorithmSHA1,
})
if err != nil {
panic(err)
}
fmt.Println("Secret URL: ", key.URL())
// 模擬生成一個一次性密碼
now := time.Now()
passcode, err := totp.GenerateCode(key.Secret(), now)
if err != nil {
panic(err)
}
// 驗證一次性密碼
valid := totp.Validate(passcode, key.Secret())
if valid {
fmt.Println("Valid passcode!")
} else {
fmt.Println("Invalid passcode!")
}
}
到此這篇關于Golang實現(xiàn)基于時間的一次性密碼TOTP的文章就介紹到這了,更多相關Go一次性密碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
golang?pprof?監(jiān)控系列?go?trace統(tǒng)計原理與使用解析
這篇文章主要為大家介紹了golang?pprof?監(jiān)控系列?go?trace統(tǒng)計原理與使用解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04
Go 并發(fā)控制 errgroup.Group的實現(xiàn)示例
本文主要介紹了Go 并發(fā)控制 errgroup.Group的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2026-04-04

