简体   繁体   English

Symfony 守卫抛出 AuthenticationException 但用户加载成功

[英]Symfony guard throws AuthenticationException but user loaded successfully

I want to implement form login with Symfony/Security to my app.我想使用 Symfony/Security 实现表单登录到我的应用程序。 I configured everything but it still doesn't work properly.我配置了所有内容,但它仍然无法正常工作。

This is my security.yaml :这是我的security.yaml

security:
    providers:
        sablon_users:
            entity:
                class: App\Entity\User
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        admin_login:
            anonymous: true
            pattern: ^/admin/auth
            form_login:
                login_path: security_login
                check_path: security_login
                csrf_token_generator: security.csrf.token_manager
                default_target_path: /admin
        admin:
            pattern: ^/admin
            guard:
                authenticators:
                    - App\Security\LoginAuthenticator
            provider: sablon_users
            logout:
                path: admin_logout
                target: security_login
        main:
            pattern: ^/
            anonymous: true

            # activate different ways to authenticate

            # http_basic: true
            # https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate

            # form_login: true
            # https://symfony.com/doc/current/security/form_login_setup.html

    # 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/auth/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin, roles: IS_AUTHENTICATED_FULLY }

    encoders:
        App\Entity\User:
            algorithm: bcrypt
            cost: 12

my routes.yaml :我的routes.yaml

admin_logout:
    path: /admin/auth/logout
admin:
    type: annotation
    resource: ../src/Controller/Admin
    prefix: /admin
site:
    type: annotation
    resource: ../src/Controller/Site

LoginAuthenticator.php :登录验证器.php :

class LoginAuthenticator extends AbstractFormLoginAuthenticator
{


    /**
     * @var EntityManagerInterface
     */
    private $em;

    /**
     * @var RouterInterface
     */
    private $router;

    /**
     * @var UserPasswordEncoderInterface
     */
    private $encoder;

    /**
     * @var CsrfTokenManagerInterface
     */
    private $csrfTokenManager;

    /**
     * @var TokenStorageInterface
     */
    private $tokenStorage;

    /**
     * LoginAuthenticator constructor.
     *
     * @param EntityManagerInterface $em
     * @param CsrfTokenManagerInterface $csrfTokenManager
     * @param RouterInterface $router
     * @param TokenStorageInterface $tokenStorage
     * @param UserPasswordEncoderInterface $encoder
     */
    public function __construct(
        EntityManagerInterface $em,
        CsrfTokenManagerInterface $csrfTokenManager,
        RouterInterface $router,
        TokenStorageInterface $tokenStorage,
        UserPasswordEncoderInterface $encoder

    )
    {
        $this->em = $em;
        $this->csrfTokenManager = $csrfTokenManager;
        $this->router = $router;
        $this->tokenStorage = $tokenStorage;
        $this->encoder = $encoder;
    }

    /**
     * @param Request $request
     * @return bool
     */
    /**
     * @return mixed
     */
    public function getCurrentUser()
    {
        $token = $this->tokenStorage->getToken();

        return $token->getUser();
    }

    /**
     * Does the authenticator support the given Request?
     *
     * If this returns false, the authenticator will be skipped.
     *
     * @param Request $request
     *
     * @return bool
     */
    public function supports(Request $request)
    {
        $isLoginSubmitRequest = $request->getPathInfo() === 'admin/auth/login' && $request->isMethod('POST');
        if(!$isLoginSubmitRequest){
            return false;
        }
        return true;
    }


    /**
     * @param Request $request
     *
     * @return mixed Any non-null value
     *
     * @throws \UnexpectedValueException If null is returned
     */
    public function getCredentials(Request $request)
    {
        $credentials = [
            'email' => $request->request->get('email'),
            'password' => $request->request->get('password'),
            'csrf_token' => $request->request->get('_csrf_token'),
        ];
        $request->getSession()->set(
            Security::LAST_USERNAME,
            $credentials['email']
        );

        return $credentials;
    }


    /**
     * @param mixed $credentials
     * @param UserProviderInterface $userProvider
     * @return User|null|object|UserInterface
     */
    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        $token = new CsrfToken('authenticate', $credentials['csrf_token']);
        if (!$this->csrfTokenManager->isTokenValid($token)) {
            throw new InvalidCsrfTokenException();
        }

        $user = $this->em->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);

        if (!$user) {
            // fail authentication with a custom error
            throw new Exception('Email could not be found.');
        }

        return $user;
    }

    /**
     * @param mixed $credentials
     * @param UserInterface $user
     *
     * @return bool
     *
     * @throws AuthenticationException
     */
    public function checkCredentials($credentials, UserInterface $user)
    {
        $password = $credentials['password'];

        return $this->encoder->isPasswordValid($user,$password);
    }

    /**
     *
     * @param Request $request
     * @param AuthenticationException $exception
     *
     * @return Response|null
     */
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {

        $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);


        return new RedirectResponse($this->router->generate('security_login'));
    }

    /**
     * @param Request $request
     * @param TokenInterface $token
     * @param string $providerKey The provider (i.e. firewall) key
     *
     * @return Response|null
     */
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        return new RedirectResponse($this->router->generate('app_homepage'));
    }

    /**
     * @return bool
     */
    public function supportsRememberMe()
    {
        return false;
    }

    /**
     * Return the URL to the login page.
     *
     * @return string
     */
    protected function getLoginUrl()
    {
        return $this->router->generate('security_login');
    }

When i try to login with correct credentials.当我尝试使用正确的凭据登录时。 It loads User and even show the username on the _profiler as authenticated (Token class: UsernamePasswordToken).它加载用户,甚至在 _profiler 上将用户名显示为已验证(令牌类:UsernamePasswordToken)。 It shows the corresponding roles for the user.它显示用户的相应角色。

However when i try to navigate '/admin' area, it redirects me to login page.但是,当我尝试导航“/admin”区域时,它会将我重定向到登录页面。 It doesn't show any error in page or console.它不会在页面或控制台中显示任何错误。

My dev.log shows the flow though:我的 dev.log 显示了流程:

  • [2019-02-13 13:58:01] request.INFO: Matched route "app_homepage". [2019-02-13 13:58:01] request.INFO:匹配路由“app_homepage”。 {"route":"app_homepage","route_parameters":{"_controller":"Symfony\\Bundle\\FrameworkBundle\\Controller\\RedirectController::urlRedirectAction","path":"/admin/","permanent":true,"scheme":null,"httpPort":8000,"httpsPort":443,"_route":"app_homepage"},"request_uri":" http://localhost:8000/admin ","method":"GET"} [] [2019-02-13 13:58:01] security.DEBUG: Checking for guard authentication credentials. {"route":"app_homepage","route_parameters":{"_controller":"Symfony\\Bundle\\FrameworkBundle\\Controller\\RedirectController::urlRedirectAction","path":"/admin/","permanent":true," scheme":null,"httpPort":8000,"httpsPort":443,"_route":"app_homepage"},"request_uri":" http://localhost:8000/admin ","method":"GET"} [] [2019-02-13 13:58:01] security.DEBUG:检查守卫身份验证凭据。 {"firewall_key":"admin","authenticators":1} [] {"firewall_key":"admin","authenticators":1} []
  • [2019-02-13 13:58:01] security.DEBUG: Checking support on guard authenticator. [2019-02-13 13:58:01] security.DEBUG:检查对守卫身份验证器的支持。 {"firewall_key":"admin","authenticator":"App\\Security\\LoginAuthenticator"} [] {"firewall_key":"admin","authenticator":"App\\Security\\LoginAuthenticator"} []
  • [2019-02-13 13:58:01] security.DEBUG: Guard authenticator does not support the request. [2019-02-13 13:58:01] security.DEBUG:Guard 验证器不支持该请求。 {"firewall_key":"admin","authenticator":"App\\Security\\LoginAuthenticator"} [] {"firewall_key":"admin","authenticator":"App\\Security\\LoginAuthenticator"} []
  • [2019-02-13 13:58:01] security.INFO: An AuthenticationException was thrown; [2019-02-13 13:58:01] security.INFO:抛出了一个AuthenticationException; redirecting to authentication entry point.重定向到身份验证入口点。 {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): A Token was not found in the TokenStorage. at /home/vagrant/Code/ project_name /vendor/symfony/security-http/Firewall/AccessListener.php:51)"} [] {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): A Token is not found in the TokenStorage. at /home/vagrant/Code/ project_name /vendor/symfony/ security-http/Firewall/AccessListener.php:51)"} []
  • [2019-02-13 13:58:01] security.DEBUG: Calling Authentication entry point. [2019-02-13 13:58:01] security.DEBUG:调用身份验证入口点。 [] [] [] []

I had the same problem: messages saying 'Guard authenticator does not support the request.', and in my case the issue was that I had symfony using https instead of http using a redirect in .htaccess.我遇到了同样的问题:消息说“保护身份验证器不支持请求。”,在我的情况下,问题是我使用 https 而不是 http 使用 symfony 使用 .htaccess 中的重定向。

In my case the solution was as simple as to go to the https webpage: - https://localhost/login在我的情况下,解决方案就像转到 https 网页一样简单: - https://localhost/login

once there the login was successful.一旦那里登录成功。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM