tokenExtractor = $tokenExtractor; $this->jwtManager = $jwtManager; $this->eventDispatcher = $eventDispatcher; $this->userProvider = $userProvider; $this->translator = $translator; } /** * {@inheritdoc} */ public function start(Request $request, AuthenticationException $authException = null): Response { $exception = new MissingTokenException('JWT Token not found', 0, $authException); $event = new JWTNotFoundEvent($exception, new JWTAuthenticationFailureResponse($exception->getMessageKey()), $request); $this->eventDispatcher->dispatch($event, Events::JWT_NOT_FOUND); return $event->getResponse(); } public function supports(Request $request): ?bool { return false !== $this->getTokenExtractor()->extract($request); } /** * @return Passport */ public function doAuthenticate(Request $request) /*: Passport */ { $token = $this->getTokenExtractor()->extract($request); if ($token === false) { throw new \LogicException('Unable to extract a JWT token from the request. Also, make sure to call `supports()` before `authenticate()` to get a proper client error.'); } try { if (!$payload = $this->jwtManager->parse($token)) { throw new InvalidTokenException('Invalid JWT Token'); } } catch (JWTDecodeFailureException $e) { if (JWTDecodeFailureException::EXPIRED_TOKEN === $e->getReason()) { throw new ExpiredTokenException(); } throw new InvalidTokenException('Invalid JWT Token', 0, $e); } $idClaim = $this->jwtManager->getUserIdClaim(); if (!isset($payload[$idClaim])) { throw new InvalidPayloadException($idClaim); } $passport = new SelfValidatingPassport( new UserBadge( (string)$payload[$idClaim], function ($userIdentifier) use ($payload) { return $this->loadUser($payload, $userIdentifier); } ) ); $passport->setAttribute('payload', $payload); $passport->setAttribute('token', $token); return $passport; } public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response { return null; } public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response { $errorMessage = strtr($exception->getMessageKey(), $exception->getMessageData()); if (null !== $this->translator) { $errorMessage = $this->translator->trans($exception->getMessageKey(), $exception->getMessageData(), 'security'); } $response = new JWTAuthenticationFailureResponse($errorMessage); if ($exception instanceof ExpiredTokenException) { $event = new JWTExpiredEvent($exception, $response, $request); $eventName = Events::JWT_EXPIRED; } else { $event = new JWTInvalidEvent($exception, $response, $request); $eventName = Events::JWT_INVALID; } $this->eventDispatcher->dispatch($event, $eventName); return $event->getResponse(); } /** * Gets the token extractor to be used for retrieving a JWT token in the * current request. * * Override this method for adding/removing extractors to the chain one or * returning a different {@link TokenExtractorInterface} implementation. */ protected function getTokenExtractor(): TokenExtractorInterface { return $this->tokenExtractor; } /** * Gets the jwt manager. */ protected function getJwtManager(): JWTTokenManagerInterface { return $this->jwtManager; } /** * Gets the event dispatcher. */ protected function getEventDispatcher(): EventDispatcherInterface { return $this->eventDispatcher; } /** * Gets the user provider. */ protected function getUserProvider(): UserProviderInterface { return $this->userProvider; } /** * Loads the user to authenticate. * * @param array $payload The token payload * @param string $identity The key from which to retrieve the user "identifier" */ protected function loadUser(array $payload, string $identity): UserInterface { if ($this->userProvider instanceof PayloadAwareUserProviderInterface) { if (method_exists($this->userProvider, 'loadUserByIdentifierAndPayload')) { return $this->userProvider->loadUserByIdentifierAndPayload($identity, $payload); } else { return $this->userProvider->loadUserByUsernameAndPayload($identity, $payload); } } if ($this->userProvider instanceof ChainUserProvider) { foreach ($this->userProvider->getProviders() as $provider) { try { if ($provider instanceof PayloadAwareUserProviderInterface) { if (method_exists(PayloadAwareUserProviderInterface::class, 'loadUserByIdentifierAndPayload')) { return $provider->loadUserByIdentifierAndPayload($identity, $payload); } else { return $provider->loadUserByUsernameAndPayload($identity, $payload); } } return $provider->loadUserByIdentifier($identity); // More generic call to catch both UsernameNotFoundException for SF<5.3 and new UserNotFoundException } catch (AuthenticationException $e) { // try next one } } if (!class_exists(UserNotFoundException::class)) { $ex = new UsernameNotFoundException(sprintf('There is no user with username "%s".', $identity)); $ex->setUsername($identity); } else { $ex = new UserNotFoundException(sprintf('There is no user with identifier "%s".', $identity)); $ex->setUserIdentifier($identity); } throw $ex; } if (method_exists($this->userProvider, 'loadUserByIdentifier')) { return $this->userProvider->loadUserByIdentifier($identity); } else { return $this->userProvider->loadUserByUsername($identity); } } public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface { if (!$passport instanceof Passport) { throw new \LogicException(sprintf('Expected "%s" but got "%s".', Passport::class, get_debug_type($passport))); } $token = new JWTPostAuthenticationToken($passport->getUser(), $firewallName, $passport->getUser()->getRoles(), $passport->getAttribute('token')); $this->eventDispatcher->dispatch(new JWTAuthenticatedEvent($passport->getAttribute('payload'), $token), Events::JWT_AUTHENTICATED); return $token; } public function createToken(Passport $passport, string $firewallName): TokenInterface { $token = new JWTPostAuthenticationToken($passport->getUser(), $firewallName, $passport->getUser()->getRoles(), $passport->getAttribute('token')); $this->eventDispatcher->dispatch(new JWTAuthenticatedEvent($passport->getAttribute('payload'), $token), Events::JWT_AUTHENTICATED); return $token; } }