简体   繁体   English

symfony 5 的 getUser() 身份验证问题

[英]symfony 5 authentification problem with getUser()

I am trying to work with Symfony 5 and the security component and I am blocked on a bug.我正在尝试使用 Symfony 5 和安全组件,但由于错误而被阻止。 the bug is on authentification success after redirection, $this->getUser() return null but at the same time, the development panel show me my role (which is store in database)该错误是重定向后身份验证成功, $this->getUser()返回 null 但同时,开发面板显示我的角色(存储在数据库中)

my security.yaml:我的 security.yaml:


security:
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        in_database:
            entity:
                class: App\Entity\User
                property: email

    role_hierarchy:
        ROLE_CLIENT:      ROLE_USER
        ROLE_ADMIN:       ROLE_CLIENT
        ROLE_DEV: [ROLE_CLIENT, ROLE_ADMIN]

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true
            provider: in_database
            form_login:
                check_path: app_login
                login_path: app_login
                default_target_path:  /test
                username_parameter: email
                password_parameter: password
                csrf_parameter: _csrf_security_token
                csrf_token_id: a_private_string
            logout:
                path: app_logout
                target: app_login


            # 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: ^/backoffice, roles: ROLE_ADMIN }
        - { path: ^/profile, roles: ROLE_USER }
    encoders:
        App\Entity\User: plaintext

And I did not modify the User entity.而且我没有修改 User 实体。

edit编辑

Following advices, I added those lines in my security.yaml:按照建议,我在 security.yaml 中添加了这些行:

guard:
    authenticators:
        - App\Security\LoginFormAuthentificator

And the LoginFormAuthentificator file (sorry it will be long)和 LoginFormAuthentificator 文件(对不起,它会很长)

<?php

namespace App\Security;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;

use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;

class LoginFormAuthentificator extends AbstractFormLoginAuthenticator {
    use TargetPathTrait;

    private $entityManager;
    private $router;
    private $csrfTokenManager;
    private $passwordEncoder;

    public function __construct(EntityManagerInterface $entityManager, RouterInterface $router, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder){
        $this->entityManager = $entityManager;
        $this->router = $router;
        $this->csrfTokenManager = $csrfTokenManager;
        $this->passwordEncoder = $passwordEncoder;
    }

    public function supports(Request $request){
        return 'app_login' === $request->attributes->get('_route') && $request->isMethod('POST');
    }

    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;
    }

    public function getUser($credentials, UserProviderInterface $userProvider){
        $token = new CsrfToken('authenticate', $credentials['csrf_token']);
        if(!$this->csrfTokenManager->isTokenValid($token)){
            throw new InvalidCsrfTokenException();
        }


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

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

        return $user;
    }

    public function checkCredentials($credentials, UserInterface $user){
        return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey){
        if($targetPath = $this->getTargetPath($request->getSession(), $providerKey)){

            return new RedirectResponse($targetPath);
        }

        return new RedirectResponse($this->router->generate('BackOffice_home_index'));
        // throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
    }

    protected function getLoginUrl(){
        return $this->router->generate('app_login');
    }
}

Thank you so much for help and time.非常感谢您的帮助和时间。

After some debugging, I found that you implement Serializable interface to your User class.经过一些调试,我发现您为User类实现了Serializable接口。 With this approach, methods from this interface should returns correct data, because User object will be serialized to the session by these methods.使用这种方法,来自该接口的方法应该返回正确的数据,因为User对象将被这些方法序列化到会话中。 In your case methods, serialize and unserialize were empty, which causing null value stored in session.在您的案例方法中, serialize和反unserialize serialize空,这导致会话中存储空值。 So you should remove Serializable interface and it's methods from your User class (in this case application store some default fields in session), or implement at least minimal functionality to this methods:因此,您应该从User类中删除Serializable接口及其方法(在这种情况下,应用程序将一些默认字段存储在会话中),或者至少为这些方法实现最少的功能:

public function serialize(){
    return serialize([
        $this->id,
        $this->email,
        $this->password
    ]); 
}

public function unserialize($serialized){
    list(
        $this->id, 
        $this->email, 
        $this->password
    ) = unserialize($serialized, ['allowed_classes' => false]);
}

also, add return value to getUsername method implemented from UserInterface , eg另外,将返回值添加到从UserInterface实现的getUsername方法中,例如

public function getUsername(){
    return $this->email;
}

More information here and here更多信息在这里这里

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

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