服务端和客户端怎么接入 TOTP 二次验证?Go、PHP、JS 三份示例代码
最后更新:2026/9/21
“研发同学福利:服务端接入以golang和php为例,客户端接入以js为例,有代码有案例,告诉你如何接入TOTP身份验证。”
一、服务端:Go 语言如何接入 TOTP 验证器?
Talk is cheap, show me the code.
话不多说,直接上示例代码:
package main
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base32"
"encoding/binary"
"fmt"
"math"
"strconv"
"strings"
"time"
)
func main() {
// 生成密钥
secret := generateSecret()
fmt.Println("Secret Key:", secret)
// 生成一次性密码
otp := generateOTP(secret)
fmt.Println("One-Time Password:", otp)
// 验证用户输入的密码
input := "123456" // 用户输入的密码,一般通过POST请求,提交给服务端
valid := verifyOTP(secret, input)
fmt.Println("Password is valid:", valid)
}
func generateSecret() string {
// 生成10个随机字节作为密钥
secret := make([]byte, 10)
_, err := rand.Read(secret)
if err != nil {
panic(err)
}
// 将密钥进行Base32编码
encoded := base32.StdEncoding.EncodeToString(secret)
return encoded
}
func generateOTP(secret string) string {
// 获取当前时间的时间戳(以30秒为单位)
timestamp := time.Now().Unix() / 30
// 将时间戳转换为8字节的大端字节序
message := make([]byte, 8)
binary.BigEndian.PutUint64(message, uint64(timestamp))
// 使用HMAC-SHA1算法计算哈希值
key, _ := base32.StdEncoding.DecodeString(secret)
mac := hmac.New(sha1.New, key)
mac.Write(message)
hash := mac.Sum(nil)
// 获取哈希值的最后4位
offset := hash[len(hash)-1] & 0x0F
// 从哈希值中获取4个字节,并转换为大端字节序
sub := hash[offset : offset+4]
sub[0] = sub[0] & 0x7F
otp := binary.BigEndian.Uint32(sub)
// 将OTP转换为6位数字密码
password := strconv.Itoa(int(otp % 1000000))
for len(password) < 6 {
password = "0" + password
}
return password
}
func verifyOTP(secret string, input string) bool {
// 获取当前时间的时间戳(以30秒为单位)
timestamp := time.Now().Unix() / 30
// 验证输入的密码是否与生成的密码匹配
for i := -1; i <= 1; i++ {
otp := generateOTP(secret, timestamp+int64(i))
if otp == input {
return true
}
}
return false
}
二、服务端:PHP 如何接入 TOTP 验证器?
懂代码的,还是直接看代码吧:
<?php
function generateSecret() {
// 生成10个随机字节作为密钥
$secret = random_bytes(10);
// 将密钥进行Base32编码
$encoded = base32_encode($secret);
return $encoded;
}
function generateOTP($secret) {
// 获取当前时间的时间戳(以30秒为单位)
$timestamp = floor(time() / 30);
// 将时间戳转换为8字节的大端字节序
$message = pack("N*", 0, 0, 0, 0, 0, $timestamp);
// 使用HMAC-SHA1算法计算哈希值
$key = base32_decode($secret);
$hash = hash_hmac("sha1", $message, $key, true);
// 获取哈希值的最后4位
$offset = ord(substr($hash, -1)) & 0x0F;
// 从哈希值中获取4个字节,并转换为大端字节序
$sub = substr($hash, $offset, 4);
$sub[0] = $sub[0] & 0x7F;
$otp = unpack("N", $sub)[1];
// 将OTP转换为6位数字密码
$password = str_pad($otp % 1000000, 6, "0", STR_PAD_LEFT);
return $password;
}
function verifyOTP($secret, $input) {
// 获取当前时间的时间戳(以30秒为单位)
$timestamp = floor(time() / 30);
// 验证输入的密码是否与生成的密码匹配
for ($i = -1; $i <= 1; $i++) {
$otp = generateOTP($secret, $timestamp + $i);
if ($otp == $input) {
return true;
}
}
return false;
}
// 生成密钥
$secret = generateSecret();
echo "Secret Key: " . $secret . "\n";
// 生成一次性密码
$otp = generateOTP($secret);
echo "One-Time Password: " . $otp . "\n";
// 验证用户输入的密码
$input = "123456"; // 用户输入的密码
$valid = verifyOTP($secret, $input);
echo "Password is valid: " . ($valid ? "true" : "false") . "\n";
?>
三、前端:WEB 端如何接入 TOTP 验证器?
以 js 接入为例,上代码:
function generateOTP(secret) {
// 获取当前时间的时间戳(以30秒为单位)
var timestamp = Math.floor(Date.now() / 1000 / 30);
// 将时间戳转换为8字节的大端字节序
var message = new Uint8Array(8);
for (var i = 0; i < 8; i++) {
message[7 - i] = timestamp & 0xFF;
timestamp >>= 8;
}
// 使用HMAC-SHA1算法计算哈希值
var key = base32.decode(secret);
var hmac = new sjcl.misc.hmac(key, sjcl.hash.sha1);
var hash = hmac.encrypt(message);
// 获取哈希值的最后4位
var offset = hash[19] & 0x0F;
// 从哈希值中获取4个字节,并转换为大端字节序
var sub = hash.slice(offset, offset + 4);
sub[0] &= 0x7
通过以上案例,相信大家已经熟悉了客户端和服务端分别如何接入 TOTP 验证器,给自己公司的应用加上一道坚固的安全防护了。
快来给公司的应用或者网站,加上动态口令验证吧!
遇到使用问题,或者有建议反馈,可以加客服微信,微信号:free2fa

