使用新身份验证方法的 Symfony 简单登录表单不起作用

dom*_*kat 5 php authentication symfony

我在设置新的 symfony 应用程序时遇到问题,我确信它与新的基于身份验证器的安全系统有关。

  1. 我安装了一个新的 symfony 应用程序,版本 5.3.6。
  2. 安装安全包composer require symfony/security-bundle(https://symfony.com/doc/current/security.html)。按照那里的所有步骤进行操作。
  3. 之后,我想按照本指南构建一个简单的登录表单: https: //symfony.com/doc/current/security/form_login_setup.html。php bin/console make:auth我像往常一样执行了生成所有文件并更新我的 security.yml 的命令。在这里,我注意到该命令没有生成 Guard 身份验证器(因为我知道它已经过时了),而是生成了新的(https://symfony.com/doc/current/security/authenticator_manager.html)。
  4. 之后,我转到我的 /login 页面,输入凭据并提交表单。页面重新加载,什么也没有。没有错误消息,我仍然没有经过身份验证。我没有执行任何其他步骤,因为它应该按原样工作?好吧,至少旧的 Guard 身份验证是这样工作的。然而,这个新的身份验证系统似乎不起作用。我错过了什么吗?

我的文件:

LoginFormAuthenticator.php

class LoginFormAuthenticator extends AbstractLoginFormAuthenticator{

use TargetPathTrait;

public const LOGIN_ROUTE = 'app_login';

private UrlGeneratorInterface $urlGenerator;

public function __construct(UrlGeneratorInterface $urlGenerator)
{
    $this->urlGenerator = $urlGenerator;
}

public function authenticate(Request $request): PassportInterface
{
    $email = $request->request->get('email', '');

    $request->getSession()->set(Security::LAST_USERNAME, $email);

    return new Passport(
        new UserBadge($email),
        new PasswordCredentials($request->request->get('password', '')),
        [
            new CsrfTokenBadge('authenticate', $request->get('_csrf_token')),
        ]
    );
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
    if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
        return new RedirectResponse($targetPath);
    }

    // For example:
    return new RedirectResponse($this->urlGenerator->generate('dashboard'));
}

protected function getLoginUrl(Request $request): string
{
    return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
Run Code Online (Sandbox Code Playgroud)

}

安全控制器.php

class SecurityController extends AbstractController{

/**
 * @Route("/login", name="app_login")
 */
public function login(AuthenticationUtils $authenticationUtils): Response
{
    // if ($this->getUser()) {
    //     return $this->redirectToRoute('target_path');
    // }

    // get the login error if there is one
    $error = $authenticationUtils->getLastAuthenticationError();
    // last username entered by the user
    $lastUsername = $authenticationUtils->getLastUsername();

    return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}

/**
 * @Route("/logout", name="app_logout")
 */
public function logout()
{
    throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
Run Code Online (Sandbox Code Playgroud)

}

安全.yml

security:
# https://symfony.com/doc/current/security/experimental_authenticators.html
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#c-hashing-passwords
password_hashers:
    Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
    App\Entity\User:
        algorithm: auto

# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
    # used to reload user from session & other features (e.g. switch_user)
    app_user_provider:
        entity:
            class: App\Entity\User
            property: email
firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    main:
        lazy: true
        provider: app_user_provider
        custom_authenticator: App\Security\LoginFormAuthenticator
        logout:
            path: app_logout
            # where to redirect after logout
            # target: app_any_route

        # activate different ways to authenticate
        # https://symfony.com/doc/current/security.html#firewalls-authentication

        # https://symfony.com/doc/current/security/impersonating_user.html
        # switch_user: true

# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
    - { path: ^/admin, roles: ROLE_ADMIN }
    # - { path: ^/profile, roles: ROLE_USER }
Run Code Online (Sandbox Code Playgroud)

dom*_*kat 8

问题出现在 AbstractLoginFormAuthenticator 类的 support() 方法中。该方法检查 getLoginUrl() 方法是否返回完整的 URI,而 getPathInfo() 则在 URI 后提供额外的路径信息。我必须重写 support() 方法,并使用 getRequestUri() 覆盖 getPathInfo() ,它起作用了。

public function supports(Request $request): bool
{
    return $request->isMethod('POST') && $this->getLoginUrl($request) === $request->getRequestUri();
}
Run Code Online (Sandbox Code Playgroud)