服务端和客户端怎么接入 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

free2fa二次验证码小程序码,微信扫码即可打开使用

Free2FA 二次验证码微信小程序码

在微信中打开 Free2FA 小程序

微信扫码即可使用,无需下载 App

更多打开方式 →