在 PHP 中实现一次性密码(OTP)验证可以通过以下步骤完成。这里以 christian-riesen/otp
库为例,演示 TOTP(基于时间的 OTP)的实现流程:
1. 安装库
composer require christian-riesen/otp
2. 生成密钥
use OTP\OTP;
// 生成一个随机密钥(Base32 格式)
$secret = OTP::generateSecret();
// 例如: "JDJESF4W2N4XU7BZ"
3. 生成 OTP 验证码
use OTP\TOTP;
$totp = new TOTP($secret);
$currentCode = $totp->getCode(); // 获取当前时间窗口的 OTP 验证码
4. 验证用户输入
$userInput = $_POST['otp_code']; // 用户提交的验证码
// 验证用户输入的 OTP 是否有效(允许时间窗口偏差)
$isValid = $totp->verify($userInput, window: 1); // window=1 允许前后 30 秒有效
if ($isValid) {
echo "验证成功!";
} else {
echo "验证失败!";
}
5. 集成到实际场景
示例:生成二维码(方便用户绑定)
使用 endroid/qr-code
库生成 Google Authenticator 可扫描的二维码:
composer require endroid/qr-code
use Endroid\QrCode\QrCode;
use Endroid\QrCode\Writer\PngWriter;
// 生成 OTP 绑定 URI(标准格式)
$issuer = "YourAppName";
$accountName = "user@example.com";
$otpUri = $totp->getUri($accountName, $issuer);
// 生成二维码图片
$qrCode = new QrCode($otpUri);
$writer = new PngWriter();
$result = $writer->write($qrCode);
// 输出二维码到浏览器
header('Content-Type: ' . $result->getMimeType());
echo $result->getString();
关键注意事项
-
密钥存储
生成的$secret
必须安全存储(如加密后存数据库),并在用户绑定时与账号关联。 -
时间同步
TOTP 依赖服务器与客户端时间一致性,确保服务器时间准确(可同步 NTP)。 -
容错窗口
window
参数控制允许的时间偏差范围。window=1
表示允许当前时间 ±30 秒有效。 -
用户引导
提供二维码或手动输入密钥选项,兼容 Google Authenticator/Microsoft Authenticator 等应用。
文档参考
- 库文档:christian-riesen/otp GitHub
- OTP 标准:RFC 6238 (TOTP)
通过以上步骤,你可以快速实现基于 PHP 的双因素认证(2FA)功能。