* @author Robin Chalas */ class JWTManager implements JWTManagerInterface, JWTTokenManagerInterface { /** * @var JWTEncoderInterface */ protected $jwtEncoder; /** * @var EventDispatcherInterface */ protected $dispatcher; /** * @var string * * @deprecated since v2.15 */ protected $userIdentityField; /** * @var string */ protected $userIdClaim; /** * @param string|null $userIdClaim */ public function __construct(JWTEncoderInterface $encoder, EventDispatcherInterface $dispatcher, $userIdClaim = null) { $this->jwtEncoder = $encoder; $this->dispatcher = $dispatcher; $this->userIdentityField = 'username'; $this->userIdClaim = $userIdClaim; } /** * @return string The JWT token */ public function create(UserInterface $user): string { $payload = ['roles' => $user->getRoles()]; $this->addUserIdentityToPayload($user, $payload); return $this->generateJwtStringAndDispatchEvents($user, $payload); } /** * @return string The JWT token */ public function createFromPayload(UserInterface $user, array $payload): string { $payload = array_merge(['roles' => $user->getRoles()], $payload); $this->addUserIdentityToPayload($user, $payload); return $this->generateJwtStringAndDispatchEvents($user, $payload); } /** * @return string The JWT token */ private function generateJwtStringAndDispatchEvents(UserInterface $user, array $payload): string { $jwtCreatedEvent = new JWTCreatedEvent($payload, $user); $this->dispatcher->dispatch($jwtCreatedEvent, Events::JWT_CREATED); if ($this->jwtEncoder instanceof HeaderAwareJWTEncoderInterface) { $jwtString = $this->jwtEncoder->encode($jwtCreatedEvent->getData(), $jwtCreatedEvent->getHeader()); } else { $jwtString = $this->jwtEncoder->encode($jwtCreatedEvent->getData()); } $jwtEncodedEvent = new JWTEncodedEvent($jwtString); $this->dispatcher->dispatch($jwtEncodedEvent, Events::JWT_ENCODED); return $jwtString; } /** * {@inheritdoc} * @throws JWTDecodeFailureException */ public function decode(TokenInterface $token) { if (!($payload = $this->jwtEncoder->decode($token->getCredentials()))) { return false; } $event = new JWTDecodedEvent($payload); $this->dispatcher->dispatch($event, Events::JWT_DECODED); if (!$event->isValid()) { return false; } return $event->getPayload(); } /** * {@inheritdoc} */ public function parse(string $jwtToken): array { $payload = $this->jwtEncoder->decode($jwtToken); $event = new JWTDecodedEvent($payload); $this->dispatcher->dispatch($event, Events::JWT_DECODED); if (!$event->isValid()) { throw new JWTDecodeFailureException(JWTDecodeFailureException::INVALID_TOKEN, 'The token was marked as invalid by an event listener after successful decoding.'); } return $event->getPayload(); } /** * Add user identity to payload, username by default. * Override this if you need to identify it by another property. * * @param array &$payload */ protected function addUserIdentityToPayload(UserInterface $user, array &$payload) { $accessor = PropertyAccess::createPropertyAccessor(); $identityField = $this->userIdClaim ?: $this->userIdentityField; if ($user instanceof InMemoryUser && 'username' === $identityField) { $payload[$identityField] = $accessor->getValue($user, 'userIdentifier'); return; } $payload[$identityField] = $accessor->getValue($user, $accessor->isReadable($user, $identityField) ? $identityField : 'user_identifier'); } /** * {@inheritdoc} */ public function getUserIdentityField(): string { if (0 === func_num_args() || func_get_arg(0)) { trigger_deprecation('lexik/jwt-authentication-bundle', '2.15', 'The "%s()" method is deprecated.', __METHOD__); } return $this->userIdentityField; } /** * {@inheritdoc} */ public function setUserIdentityField($field) { if (1 >= func_num_args() || func_get_arg(1)) { trigger_deprecation('lexik/jwt-authentication-bundle', '2.15', 'The "%s()" method is deprecated.', __METHOD__); } $this->userIdentityField = $field; } /** * @return string */ public function getUserIdClaim(): ?string { return $this->userIdClaim; } }