I am trying to work with Symfony 5 and the security component and I am blocked on a bug. 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)
my security.yaml:
security: # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers providers: in_database: entity: class: AppEntityUser 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: AppEntityUser: plaintext
And I did not modify the User entity.
edit
Following advices, I added those lines in my security.yaml:
guard: authenticators: - AppSecurityLoginFormAuthentificator
And the LoginFormAuthentificator file (sorry it will be long)
<?php namespace AppSecurity; use AppEntityUser; use DoctrineORMEntityManagerInterface; use SymfonyComponentHttpFoundationRedirectResponse; use SymfonyComponentHttpFoundationRequest; use SymfonyComponentRoutingRouterInterface; use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface; use SymfonyComponentSecurityCoreEncoderUserPasswordEncoderInterface; use SymfonyComponentSecurityCoreExceptionCustomUserMessageAuthenticationException; use SymfonyComponentSecurityCoreExceptionInvalidCsrfTokenException; use SymfonyComponentSecurityCoreSecurity; use SymfonyComponentSecurityCoreUserUserInterface; use SymfonyComponentSecurityCoreUserUserProviderInterface; use SymfonyComponentSecurityCsrfCsrfToken; use SymfonyComponentSecurityCsrfCsrfTokenManagerInterface; use SymfonyComponentSecurityGuardAuthenticatorAbstractFormLoginAuthenticator; use SymfonyComponentSecurityHttpUtilTargetPathTrait; 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.
Advertisement
Answer
After some debugging, I found that you implement Serializable
interface to your User
class. With this approach, methods from this interface should returns correct data, because User
object will be serialized to the session by these methods. In your case methods, serialize
and unserialize
were empty, which causing null value stored in session. 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:
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
, e.g.
public function getUsername(){ return $this->email; }