golang实现TOTP和HOTP双因素认证的插件库otpgo的使用
golang实现TOTP和HOTP双因素认证的插件库otpgo的使用
otpgo是一个用于Go语言的HMAC-Based和Time-Based一次性密码(HOTP和TOTP)库,实现了RFC 4226和RFC 6238标准。
支持的操作
- 生成HOTP和TOTP代码
- 验证HOTP和TOTP代码
- 将OTP配置导出为Google Authenticator URI
- 将OTP配置导出为QR码图像(用于在认证应用中注册密钥)
- 将OTP配置导出为JSON
使用示例
生成代码
最简单的生成代码方式是创建HOTP/TOTP结构体并调用Generate()
方法:
// HMAC-Based
// 使用所有默认值,计数器从0开始
h := otpgo.HOTP{}
token, _ := h.Generate()
// 增加计数器并生成下一个代码
h.Counter++
token2, _ := h.Generate()
// Time-Based
// 使用所有默认值
t := otpgo.TOTP{}
token, _ := t.Generate()
每种类型都允许自定义。对于HMAC-Based令牌,可以指定:
- Key: 密钥字符串,base32编码
- Counter: 无符号整数
- Leeway: 无符号整数
- Algorithm:
HmacSHA1
、HmacSHA256
或HmacSHA512
之一 - Length:
Length1
到Length8
对于Time-Based令牌,可以指定:
- Key: 密钥字符串,base32编码
- Period: 整数,周期长度(秒)
- Delay: 整数,验证可接受的步数
- Algorithm:
HmacSHA1
、HmacSHA256
或HmacSHA512
之一 - Length:
Length1
到Length8
验证代码
收到用户令牌后,可以通过指定预期参数并调用Validate(token string)
来验证它:
// HMAC-Based
h := otpgo.HOTP{
Key: "my-secret-key",
Counter: 123, // 预期计数器
}
ok, _ := h.Validate("the-token")
// Time-Based
t := otpgo.TOTP{
Key: "my-secret-key",
}
ok, _ = t.Validate("the-token")
调用HOTP.Validate()
时要注意,如果验证成功,内部计数器会增加,这样下一个有效令牌将对应于增加的计数器。
与认证应用注册
大多数认证应用会给用户2个选项来注册新账户:扫描包含OTP生成所有配置和密钥的QR码,或手动输入密钥和其他信息(如用户名和发行者)。
QR码
要生成QR码,只需获取KeyUri
并调用QRCode
方法:
otp := otpgo.TOTP{}
base64EncodedQRImage, _ := otp.
KeyUri("john.doe@example.org", "A Company").
QRCode()
// 然后使用base64EncodedQRImage,例如:发送给客户端显示为图像
手动注册
手动注册通常需要用户手动输入OTP配置参数。KeyUri类型可以轻松JSON编码,然后将参数发送给外部调用者或其他地方。
otp := otpgo.TOTP{
Key: "YOUR_KEY",
Period: 30,
Delay: 1,
Algorithm: config.HmacSHA1,
Length: 6
}
ku := otp.KeyUri("john.doe@example.org", "A Company")
jsonKeyUri, _ := json.Marshal(ku)
// 然后使用jsonKeyUri,例如:发送给客户端进行进一步处理
默认值
如果调用者在生成OTP时不提供自定义配置,库将确保以下默认值(任何空值将被填充)。
HOTP参数
参数 | 默认值 |
---|---|
Leeway | 1 计数器上下 |
Hash / Algorithm | SHA1 |
Length | 6 |
Key | 64 随机字节 base32 编码 |
TOTP参数
参数 | 默认值 |
---|---|
Period | 30 秒 |
Delay | 1 周期上下 |
Hash / Algorithm | SHA1 |
Length | 6 |
Key | 64 随机字节 base32 编码 |
更多关于golang实现TOTP和HOTP双因素认证的插件库otpgo的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang实现TOTP和HOTP双因素认证的插件库otpgo的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用otpgo实现Golang中的TOTP和HOTP双因素认证
otpgo是一个Golang库,用于实现基于时间的一次性密码(TOTP)和基于HMAC的一次性密码(HOTP)的双因素认证功能。下面我将介绍如何使用这个库。
安装otpgo
首先安装otpgo库:
go get github.com/jltorresm/otpgo
TOTP实现示例
TOTP是基于时间的一次性密码算法,常用于Google Authenticator等应用。
package main
import (
"fmt"
"github.com/jltorresm/otpgo"
"github.com/jltorresm/otpgo/totp"
"time"
)
func main() {
// 1. 生成TOTP密钥
key, err := totp.GenerateKey(totp.GenerateKeyOpts{
Issuer: "MyApp",
AccountName: "user@example.com",
})
if err != nil {
panic(err)
}
fmt.Printf("密钥: %s\n", key.Secret())
fmt.Printf("二维码URI: %s\n", key.URI())
// 2. 生成当前时间的TOTP密码
code, err := totp.GenerateCode(key.Secret(), time.Now())
if err != nil {
panic(err)
}
fmt.Printf("当前TOTP密码: %s\n", code)
// 3. 验证TOTP密码
valid, err := totp.ValidateCustom(code, key.Secret(), time.Now(), totp.ValidateOpts{
Digits: 6, // 6位数字
Period: 30, // 30秒有效期
Skew: 1, // 允许前后1个时间窗口
Algorithm: otpgo.SHA1, // 使用SHA1算法
})
if err != nil {
panic(err)
}
fmt.Printf("验证结果: %v\n", valid)
}
HOTP实现示例
HOTP是基于计数器的一次性密码算法。
package main
import (
"fmt"
"github.com/jltorresm/otpgo"
"github.com/jltorresm/otpgo/hotp"
)
func main() {
// 1. 生成HOTP密钥
key, err := hotp.GenerateKey(hotp.GenerateKeyOpts{
Issuer: "MyApp",
AccountName: "user@example.com",
})
if err != nil {
panic(err)
}
fmt.Printf("密钥: %s\n", key.Secret())
fmt.Printf("二维码URI: %s\n", key.URI())
// 2. 生成指定计数器的HOTP密码
counter := uint64(42) // 计数器值
code, err := hotp.GenerateCode(key.Secret(), counter)
if err != nil {
panic(err)
}
fmt.Printf("计数器%d的HOTP密码: %s\n", counter, code)
// 3. 验证HOTP密码
valid, err := hotp.ValidateCustom(code, counter, key.Secret(), hotp.ValidateOpts{
Digits: 6, // 6位数字
Algorithm: otpgo.SHA1, // 使用SHA1算法
})
if err != nil {
panic(err)
}
fmt.Printf("验证结果: %v\n", valid)
}
实际应用场景
在实际应用中,你通常会:
- 在用户注册时生成密钥并保存到数据库
- 提供二维码让用户用验证器应用扫描
- 在登录时要求用户输入验证码并验证
// 用户注册时生成TOTP密钥
func generateTOTPForUser(userID string) (string, string, error) {
key, err := totp.GenerateKey(totp.GenerateKeyOpts{
Issuer: "MyApp",
AccountName: userID,
})
if err != nil {
return "", "", err
}
// 保存key.Secret()到用户数据库
return key.Secret(), key.URI(), nil
}
// 验证用户输入的TOTP
func verifyTOTP(userID, userCode string) (bool, error) {
// 从数据库获取用户保存的secret
secret := getUserSecret(userID)
valid, err := totp.ValidateCustom(userCode, secret, time.Now(), totp.ValidateOpts{
Digits: 6,
Period: 30,
Skew: 1,
Algorithm: otpgo.SHA1,
})
return valid, err
}
注意事项
- 密钥(secret)必须安全存储,建议加密后存入数据库
- 考虑实现备用代码机制,以防用户丢失设备
- 对于HOTP,需要安全地存储和更新计数器值
- 在生产环境中,应该限制验证尝试次数防止暴力破解
otpgo库提供了灵活的参数配置,你可以根据需要调整密码长度、哈希算法、时间窗口等参数来满足不同的安全需求。