You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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」时,我们需要生成专属密钥、展示二维码,再验证用户的绑定操作:

  1. 生成唯一的加密密钥(secret),这个密钥要存在用户表的字段里(比如新增gauth_secretgauth_enabled两个字段,前者存密钥,后者标记是否启用)。
  2. 生成二维码的Data URI,直接用img标签就能在页面显示。
  3. 让用户输入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:

  1. 如果未启用,直接完成登录。
  2. 如果已启用,跳转到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

火山引擎 最新活动