You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Api Platform中Google Authenticator双因素认证:2FA码提交端点配置问题

解决Api Platform + JWT + Scheb 2FA验证码提交端点配置问题

核心问题说明

SchebTwoFactorBundle默认提供的是适配Web表单的2FA路由,不适合RESTful API场景。你需要自定义一个API端点来处理2FA验证码的提交,并结合JWT完成最终认证。

步骤1:创建2FA验证控制器

新建src/Controller/TwoFactorAuthenticationController.php,处理验证码提交请求:

<?php

namespace App\Controller;

use Scheb\TwoFactorBundle\Security\Authentication\Token\TwoFactorTokenInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;

class TwoFactorAuthenticationController extends AbstractController
{
    public function __construct(
        private TokenStorageInterface $tokenStorage,
        private AuthenticationSuccessHandlerInterface $successHandler,
        private AuthenticationFailureHandlerInterface $failureHandler
    ) {}

    public function verify(Request $request): JsonResponse
    {
        $token = $this->tokenStorage->getToken();
        if (!$token instanceof TwoFactorTokenInterface) {
            return new JsonResponse(['error' => '无待处理的2FA认证请求'], 400);
        }

        $code = $request->request->get('code');
        if (!$code) {
            return new JsonResponse(['error' => '缺少2FA验证码'], 400);
        }

        try {
            // 验证验证码并生成已认证令牌
            $authToken = $token->createAuthenticatedToken($code);
            $this->tokenStorage->setToken($authToken);

            // 调用成功处理器生成正式JWT
            $response = $this->successHandler->onAuthenticationSuccess($request, $authToken);
            return JsonResponse::fromJsonString($response->getContent(), $response->getStatusCode());
        } catch (AuthenticationException $e) {
            // 验证码错误返回失败响应
            $response = $this->failureHandler->onAuthenticationFailure($request, $e);
            return JsonResponse::fromJsonString($response->getContent(), $response->getStatusCode());
        }
    }
}

步骤2:配置API端点路由

在config/routes.yaml中添加自定义2FA验证路由:

app_2fa_verify:
    path: /api/2fa/verify
    methods: [POST]
    controller: App\Controller\TwoFactorAuthenticationController::verify

步骤3:调整Security配置

修改config/packages/security.yaml,确保firewall支持2FA临时状态(注意不能完全设置为stateless: true,需要保留session存储临时认证信息):

security:
    firewalls:
        main:
            pattern: ^/api
            stateless: false
            json_login:
                check_path: /api/login
                success_handler: App\Security\LoginSuccessHandler
                failure_handler: App\Security\LoginFailureHandler
            two_factor:
                provider: app_user_provider
                success_handler: App\Security\LoginSuccessHandler
                failure_handler: App\Security\LoginFailureHandler
            logout:
                path: /api/logout

步骤4:自定义登录成功处理器

新建src/Security/LoginSuccessHandler.php,区分普通登录和需要2FA的场景:

<?php

namespace App\Security;

use Scheb\TwoFactorBundle\Security\Authentication\Token\TwoFactorTokenInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;

class LoginSuccessHandler implements AuthenticationSuccessHandlerInterface
{
    public function __construct(private JWTTokenManagerInterface $jwtManager) {}

    public function onAuthenticationSuccess(Request $request, TokenInterface $token): JsonResponse
    {
        if ($token instanceof TwoFactorTokenInterface) {
            // 未完成2FA,返回提示信息
            return new JsonResponse([
                'login' => 'success',
                'two_factor_complete' => false,
                'message' => '请提交2FA验证码到 /api/2fa/verify'
            ]);
        }

        // 2FA验证完成,生成正式JWT
        $jwt = $this->jwtManager->create($token->getUser());
        return new JsonResponse([
            'login' => 'success',
            'two_factor_complete' => true,
            'token' => $jwt
        ]);
    }
}

步骤5:验证Scheb 2FA基础配置

确保config/packages/scheb_2fa.yaml中Google Authenticator已启用:

scheb_two_factor:
    security_tokens:
        - Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken
        - Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken
    google:
        enabled: true
        server_name: 你的应用名称
        issuer: 你的应用名称

测试流程

  1. 发送POST请求到/api/login,提交邮箱和密码,返回{"login": "success", "two_factor_complete": false}
  2. 发送POST请求到/api/2fa/verify,提交{"code": "你的Google验证码"},验证通过后返回带JWT的响应;验证码错误则返回错误信息

内容的提问来源于stack exchange,提问作者Frederik Hulleman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 12:51:06