Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Symfony] Connexion avec plusieurs paramètres ?

    3 décembre 2020 à 15:59:43

    Bonjour à tous,

    Ce projet utilise Symfony 4.4

    Je souhaite utiliser 2 paramètres pour identifier un utilisateur, c'est à dire utiliser son email et sa compagnie (on peut donc avoir le plusieurs fois le même email mais avec une compagnie différente)

    Pour la partie connexion j'utilise le système de Symfony `guard authenticator`

    <?php
    
    namespace App\Security;
    
    use App\Entity\Company;
    use App\Entity\User;
    use Doctrine\ORM\EntityManagerInterface;
    use Symfony\Component\HttpFoundation\RedirectResponse;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
    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\Guard\PasswordAuthenticatedInterface;
    use Symfony\Component\Security\Http\Util\TargetPathTrait;
    
    class AppLoginFormAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
    {
        use TargetPathTrait;
    
        public const LOGIN_ROUTE = 'app_login';
    
        private $entityManager;
        private $urlGenerator;
        private $csrfTokenManager;
        private $passwordEncoder;
        private $request;
    
        public function __construct(
            EntityManagerInterface $entityManager,
            UrlGeneratorInterface $urlGenerator,
            CsrfTokenManagerInterface $csrfTokenManager,
            UserPasswordEncoderInterface $passwordEncoder
        ) {
            $this->entityManager = $entityManager;
            $this->urlGenerator = $urlGenerator;
            $this->csrfTokenManager = $csrfTokenManager;
            $this->passwordEncoder = $passwordEncoder;
        }
    
        public function supports(Request $request)
        {
            $this->request = $request;
    
            return self::LOGIN_ROUTE === $request->attributes->get('_route')
                && $request->isMethod('POST');
        }
    
        public function getCredentials(Request $request)
        {
            $credentials = [
                'email' => $request->request->get('_username'),
                'slug' => $request->get('slug'),
                '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();
            }
    
            $company = $this->entityManager->getRepository(Company::class)->findOneBy(['slug' => $credentials['slug']]);
            $user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email'], 'company' => $company]);
    
            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']);
        }
    
        /**
         * Used to upgrade (rehash) the user's password automatically over time.
         */
        public function getPassword($credentials): ?string
        {
            return $credentials['password'];
        }
    
        public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
        {
            if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
                return new RedirectResponse($targetPath);
            }
    
            return;
    
            // For example : return new RedirectResponse($this->urlGenerator->generate('some_route'));
            throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
        }
    
        protected function getLoginUrl()
        {
            return $this->urlGenerator->generate(self::LOGIN_ROUTE, ['slug' => $this->request->get('slug')]);
        }
    }


    Si je fais un `dump` dans `onAuthenticationSuccess` pour afficher le résultat de `$token` j'ai bien le bon user.

    Le problème arrive après, quand je navigue dans mon `app`, l'utilisateur qui est chargé n'est plus le bon mais toujours le premier de la DB.

    Comment peut-on faire en sorte d'avoir le bon utilisateur chargé pendant la navigation ?


    Merci

    • Partager sur Facebook
    • Partager sur Twitter
      4 décembre 2020 à 9:19:59

      Bonjour

      Peute être il faut définir un autre attribut unique (pas email) pour le username dans la classe User et dans security.yaml

      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        4 décembre 2020 à 11:18:32

        A priori tu as un problème de modélisation. Ce n'est pas parce qu'un utilisateur se connecte avec différentes compagnies qu'il devient différents utilisateurs.
        • Partager sur Facebook
        • Partager sur Twitter
          4 décembre 2020 à 15:08:47

          Bonjour, d'abord merci pour vos réponses.

          1. Hous je vais essayer cette méthode et je te tiens au courant.

          2. MatTheCat je ne suis pas sûr de comprendre en quoi j'ai un problème de modélisation, peux-tu m'en dire plus ? Il faut savoir qu'en DB j'ai bien différentes entrées ou l'unicité de mes données ce fait avec l'email et la compagnie.

          Merci à vous 2

          • Partager sur Facebook
          • Partager sur Twitter

          [Symfony] Connexion avec plusieurs paramètres ?

          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
          • Editeur
          • Markdown