vendor/crea/security-bundle/src/Authenticator/FormAuthenticator.php line 168

Open in your IDE?
  1. <?php
  2. namespace Crea\SecurityBundle\Authenticator;
  3. use Crea\SecurityBundle\Entity\User;
  4. use Crea\SecurityBundle\Event\AuthenticationEvent;
  5. use Crea\SecurityBundle\Helper\RedirectionHelperInterface;
  6. use Crea\SecurityBundle\Provider\UserProvider;
  7. use Crea\SecurityBundle\Voter\UserVoter;
  8. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  9. use Symfony\Component\HttpFoundation\JsonResponse;
  10. use Symfony\Component\HttpFoundation\RedirectResponse;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  13. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  14. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  15. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  16. use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
  17. use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
  18. use Symfony\Component\Security\Core\Security;
  19. use Symfony\Component\Security\Core\User\UserInterface;
  20. use Symfony\Component\Security\Core\User\UserProviderInterface;
  21. use Symfony\Component\Security\Csrf\CsrfToken;
  22. use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
  23. use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
  24. use Symfony\Contracts\Translation\TranslatorInterface;
  25. class FormAuthenticator extends AbstractFormLoginAuthenticator
  26. {
  27.     private UrlGeneratorInterface $urlGenerator;
  28.     private CsrfTokenManagerInterface $csrfTokenManager;
  29.     private TranslatorInterface $translator;
  30.     private EventDispatcherInterface $eventDispatcher;
  31.     private RedirectionHelperInterface $redirectionHelper;
  32.     private UserVoter $userVoter;
  33.     private UserPasswordHasherInterface $passwordHasher;
  34.     public function __construct(UrlGeneratorInterface $urlGenerator,
  35.                                 CsrfTokenManagerInterface $csrfTokenManager,
  36.                                 TranslatorInterface $translator,
  37.                                 EventDispatcherInterface $eventDispatcher,
  38.                                 RedirectionHelperInterface $redirectionHelper,
  39.                                 UserVoter $userVoter,
  40.                                 UserPasswordHasherInterface $passwordHasher)
  41.     {
  42.         $this->urlGenerator $urlGenerator;
  43.         $this->csrfTokenManager $csrfTokenManager;
  44.         $this->translator $translator;
  45.         $this->eventDispatcher $eventDispatcher;
  46.         $this->redirectionHelper $redirectionHelper;
  47.         $this->userVoter $userVoter;
  48.         $this->passwordHasher $passwordHasher;
  49.     }
  50.     /**
  51.      * This will be called on every request and your job is to decide if the authenticator should be used for this
  52.      * request (return true) or if it should be skipped (return false).
  53.      * @inheritDoc
  54.      */
  55.     public function supports(Request $request): bool
  56.     {
  57.         return 'crea_security.login' === $request->attributes->get('_route') && $request->isMethod('POST');
  58.     }
  59.     /**
  60.      * This will be called on every request and your job is to read the token (or whatever your "authentication"
  61.      * information is) from the request and return it. These credentials are later passed as the first argument of
  62.      * getUser().
  63.      * @inheritDoc
  64.      */
  65.     public function getCredentials(Request $request)
  66.     {
  67.         $credentials = [
  68.             'username' => $request->request->get('username'),
  69.             'password' => $request->request->get('password'),
  70.             'csrf_token' => $request->request->get('_csrf_token'),
  71.         ];
  72.         $request->getSession()->set(Security::LAST_USERNAME$credentials['username']);
  73.         $authenticationEvent = new AuthenticationEvent($credentials["username"], $credentials["password"]);
  74.         $this->eventDispatcher->dispatch($authenticationEvent);
  75.         return $credentials;
  76.     }
  77.     /**
  78.      * The $credentials argument is the value returned by getCredentials(). Your job is to return an object that
  79.      * implements UserInterface. If you do, then checkCredentials() will be called. If you return null (or throw an
  80.      * AuthenticationException) authentication will fail.
  81.      * @inheritDoc
  82.      */
  83.     public function getUser($credentialsUserProviderInterface $userProvider)
  84.     {
  85.         $token = new CsrfToken('authenticate'$credentials['csrf_token']);
  86.         if (!$this->csrfTokenManager->isTokenValid($token)) {
  87.             throw new InvalidCsrfTokenException();
  88.         }
  89.         // Load / create our user however you need.
  90.         if (!$userProvider instanceof UserProvider) {
  91.             throw new CustomUserMessageAuthenticationException($this->translator->trans("login.user_provider.missing_function", [], "user"));
  92.         }
  93.         $user $userProvider->loadUserByUsername($credentials["username"]);
  94.         if (!$user) {
  95.             // fail authentication with a custom error
  96.             throw new CustomUserMessageAuthenticationException($this->translator->trans("login.bad_credentials", [], "user"));
  97.         }
  98.         if (!$this->userVoter->voteOnConnect($user)) {
  99.             throw new CustomUserMessageAuthenticationException($this->translator->trans("login.inactive", [], "user"));
  100.         }
  101.         return $user;
  102.     }
  103.     /**
  104.      * If getUser() returns a User object, this method is called. Your job is to verify if the credentials are correct.
  105.      * For a login form, this is where you would check that the password is correct for the user. To pass
  106.      * authentication, return true. If you return false (or throw an AuthenticationException), authentication will fail.
  107.      * @inheritDoc
  108.      */
  109.     public function checkCredentials($credentialsUserInterface $user): bool
  110.     {
  111.         // Check the user's password or other credentials and return true or false
  112.         // If there are no credentials to check, you can just return true
  113.         /** @var User $user */
  114.         if (!$this->passwordHasher->isPasswordValid($user$credentials["password"])) {
  115.             throw new AuthenticationException();
  116.         }
  117.         $authenticationEvent = new AuthenticationEvent($credentials["username"], $credentials["password"]);
  118.         $this->eventDispatcher->dispatch($authenticationEvent);
  119.         return true;
  120.     }
  121.     /**
  122.      * This is called after successful authentication and your job is to either return a Response object that will be
  123.      * sent to the client or null to continue the request (e.g. allow the route/controller to be called like normal).
  124.      * Since this is an API where each request authenticates itself, you want to return null.
  125.      * @inheritDoc
  126.      */
  127.     public function onAuthenticationSuccess(Request $requestTokenInterface $token$providerKey)
  128.     {
  129.         $previous $request->getSession()->get('previous');
  130.         return new RedirectResponse($previous ?: $this->redirectionHelper->getUrlAfterLogin());
  131.     }
  132.     /**
  133.      * Override to control what happens when the user hits a secure page
  134.      * but isn't logged in yet.
  135.      *
  136.      * @return RedirectResponse|JsonResponse
  137.      */
  138.     public function start(Request $requestAuthenticationException $authException null)
  139.     {
  140.         if ($request->isXmlHttpRequest()) {
  141.             return new JsonResponse([
  142.                 "statusText" => htmlentities($this->translator->trans("login.logout", [], "user")),
  143.                 "reloadPage" => true
  144.             ], 403);
  145.         }
  146.         else {
  147.             $request->getSession()->set('previous'$request->getUri());
  148.         }
  149.         return new RedirectResponse($this->getLoginUrl());
  150.     }
  151.     /**
  152.      * @inheritDoc
  153.      */
  154.     protected function getLoginUrl(): string
  155.     {
  156.         return $this->urlGenerator->generate('crea_security.login');
  157.     }
  158. }