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: HmacSHA1HmacSHA256HmacSHA512之一
  • Length: Length1Length8

对于Time-Based令牌,可以指定:

  • Key: 密钥字符串,base32编码
  • Period: 整数,周期长度(秒)
  • Delay: 整数,验证可接受的步数
  • Algorithm: HmacSHA1HmacSHA256HmacSHA512之一
  • Length: Length1Length8

验证代码

收到用户令牌后,可以通过指定预期参数并调用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

1 回复

更多关于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)
}

实际应用场景

在实际应用中,你通常会:

  1. 在用户注册时生成密钥并保存到数据库
  2. 提供二维码让用户用验证器应用扫描
  3. 在登录时要求用户输入验证码并验证
// 用户注册时生成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
}

注意事项

  1. 密钥(secret)必须安全存储,建议加密后存入数据库
  2. 考虑实现备用代码机制,以防用户丢失设备
  3. 对于HOTP,需要安全地存储和更新计数器值
  4. 在生产环境中,应该限制验证尝试次数防止暴力破解

otpgo库提供了灵活的参数配置,你可以根据需要调整密码长度、哈希算法、时间窗口等参数来满足不同的安全需求。

回到顶部