PHP网站Google Authenticator双因素认证(2FA)实现咨询
嘿,我来帮你搞定这个Google Authenticator 2FA的实现!其实你装的google-api-php-client有点大材小用了——它主要是用来调用Google的OAuth、Drive这类官方API的,专门做2FA验证的话,用更轻量专注的库会顺畅很多。我给你推荐robthree/twofactorauth,它直接支持TOTP(就是Google Authenticator用的标准),还能一键生成二维码,完全符合你的需求。下面一步步给你讲实现流程:
第一步:安装合适的依赖
先通过Composer安装这个专门的2FA库:
composer require robthree/twofactorauth
如果已经装了官方包也没关系,这个库和它不冲突,直接用就行。
第二步:个人资料页的2FA启用/关闭功能
启用2FA的流程
当用户在个人资料页点击「启用2FA」时,我们需要生成专属密钥、展示二维码,再验证用户的绑定操作:
- 生成唯一的加密密钥(secret),这个密钥要存在用户表的字段里(比如新增
gauth_secret和gauth_enabled两个字段,前者存密钥,后者标记是否启用)。 - 生成二维码的Data URI,直接用img标签就能在页面显示。
- 让用户输入Google Authenticator里的6位验证码,验证通过后把密钥存入数据库,标记2FA为启用状态。
代码示例:
// 引入库 require 'vendor/autoload.php'; use RobThree\Auth\TwoFactorAuth; // 初始化,传入你的游戏网站名称(会显示在用户的Google Authenticator里) $tfa = new TwoFactorAuth('你的游戏网站名称'); // 生成16位的随机密钥 $secret = $tfa->createSecret(16); // 把密钥暂存到session,等用户验证完再存数据库 $_SESSION['temp_gauth_secret'] = $secret; // 生成二维码的Data URI,直接放到img标签里就能显示 $qrCodeUri = $tfa->getQRCodeImageAsDataUri($user['username'], $secret); // 在页面展示二维码和验证码输入框 echo '<div>请用Google Authenticator扫描下方二维码:</div>'; echo '<img src="' . $qrCodeUri . '" alt="2FA绑定二维码">'; echo '<form method="post">'; echo '<input type="text" name="gauth_code" placeholder="输入6位验证码" maxlength="6" required>'; echo '<button type="submit" name="verify_gauth">验证并启用</button>'; echo '</form>';
验证用户提交的验证码:
if (isset($_POST['verify_gauth'])) { $userInputCode = trim($_POST['gauth_code']); $tempSecret = $_SESSION['temp_gauth_secret']; $userId = $_SESSION['user_id']; // 假设你已经保存了当前登录用户的ID if ($tfa->verifyCode($tempSecret, $userInputCode)) { // 验证成功,更新用户数据库 $stmt = $pdo->prepare("UPDATE users SET gauth_secret = ?, gauth_enabled = 1 WHERE id = ?"); $stmt->execute([$tempSecret, $userId]); // 清除临时密钥 unset($_SESSION['temp_gauth_secret']); echo '<p style="color:green;">2FA已成功启用!</p>'; } else { echo '<p style="color:red;">验证码错误,请重试!</p>'; } }
关闭2FA的流程
用户关闭2FA时,建议先验证当前的2FA验证码(确保是本人操作),然后更新数据库状态:
if (isset($_POST['disable_gauth'])) { $userInputCode = trim($_POST['gauth_code']); $userId = $_SESSION['user_id']; // 从数据库取出用户的密钥 $stmt = $pdo->prepare("SELECT gauth_secret FROM users WHERE id = ?"); $stmt->execute([$userId]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($tfa->verifyCode($user['gauth_secret'], $userInputCode)) { // 验证成功,关闭2FA $stmt = $pdo->prepare("UPDATE users SET gauth_enabled = 0, gauth_secret = NULL WHERE id = ?"); $stmt->execute([$userId]); echo '<p style="color:green;">2FA已成功关闭!</p>'; } else { echo '<p style="color:red;">验证码错误,无法关闭2FA!</p>'; } }
第三步:登录页面的2FA验证流程
登录时先验证用户名和密码,通过后检查用户是否启用了2FA:
- 如果未启用,直接完成登录。
- 如果已启用,跳转到2FA验证页面,输入验证码后完成登录。
登录页核心代码:
// 验证用户名和密码(这里用你自己的数据库逻辑) $username = trim($_POST['username']); $password = trim($_POST['password']); $stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?"); $stmt->execute([$username]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user && password_verify($password, $user['password'])) { if ($user['gauth_enabled']) { // 用户名密码正确,需要验证2FA,暂存用户ID到session $_SESSION['pending_login_id'] = $user['id']; header("Location: verify-gauth.php"); exit; } else { // 直接登录成功,设置用户session $_SESSION['user_id'] = $user['id']; header("Location: dashboard.php"); exit; } } else { echo '<p style="color:red;">用户名或密码错误!</p>'; }
2FA验证页面(verify-gauth.php)代码:
require 'vendor/autoload.php'; use RobThree\Auth\TwoFactorAuth; $tfa = new TwoFactorAuth('你的游戏网站名称'); if ($_SERVER['REQUEST_METHOD'] == 'POST') { $userInputCode = trim($_POST['gauth_code']); $userId = $_SESSION['pending_login_id']; $stmt = $pdo->prepare("SELECT gauth_secret FROM users WHERE id = ?"); $stmt->execute([$userId]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($tfa->verifyCode($user['gauth_secret'], $userInputCode)) { // 验证成功,完成登录 $_SESSION['user_id'] = $userId; unset($_SESSION['pending_login_id']); header("Location: dashboard.php"); exit; } else { $error = "2FA验证码错误,请重试!"; } } ?> <!DOCTYPE html> <html> <head> <title>验证2FA</title> </head> <body> <?php if (isset($error)) echo '<p style="color:red;">' . $error . '</p>'; ?> <form method="post"> <input type="text" name="gauth_code" placeholder="输入Google Authenticator 6位验证码" maxlength="6" required> <button type="submit">验证登录</button> </form> </body> </html>
关于你安装的
google-api-php-client 这个包其实不是用来做2FA验证的,它的定位是Google服务的API客户端(比如OAuth登录、操作Google Drive等)。如果一定要用它来实现2FA,你需要自己手动实现TOTP算法,还要找第三方二维码生成工具,非常折腾,完全没必要——上面的方案已经完美覆盖你的需求了。
内容的提问来源于stack exchange,提问作者Ronnie Oosting




