src/Security/Authentication/JWTSubscriber.php line 44
<?php
namespace App\Security\Authentication;
use Symfony\Component\EventDispatcher\EventSubscriberInterface,
Symfony\Component\HttpFoundation\RequestStack,
Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent,
Lexik\Bundle\JWTAuthenticationBundle\Event\JWTDecodedEvent,
Lexik\Bundle\JWTAuthenticationBundle\Events as LexikEvents,
Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface,
Lexik\Bundle\JWTAuthenticationBundle\Security\Authenticator\Token\JWTPostAuthenticationToken;
final class JWTSubscriber implements EventSubscriberInterface
{
const REMEMBER_ME_TTL = '30 days';
private TokenStorageInterface $tokenStorage;
private JWTTokenManagerInterface $jwtManager;
private RequestStack $requestStack;
public function __construct(
TokenStorageInterface $tokenStorage,
JWTTokenManagerInterface $jwtManager,
RequestStack $requestStack
) {
$this->tokenStorage = $tokenStorage;
$this->jwtManager = $jwtManager;
$this->requestStack = $requestStack;
}
public static function getSubscribedEvents() : array
{
return [
LexikEvents::JWT_CREATED => [
['onJWTCreated', 10],
],
// LexikEvents::JWT_DECODED => [
// ['onJWTDecoded', 10]
// ]
];
}
public function onJWTCreated(JWTCreatedEvent $event): void
{
$payload = $event->getData();
$payload['ip'] = $this->getClientIp();
$event->setData($payload);
$header = $event->getHeader();
$header['cty'] = 'JWT';
$event->setHeader($header);
$exp = $this->getExpire();
if ($exp) {
$payload['exp'] = $exp;
}
$event->setData($payload);
return;
}
public function onJWTDecoded(JWTDecodedEvent $event): void
{
$payload = $event->getPayload();
if (! isset($payload['ip']) || $payload['ip'] !== $this->getClientIp()) {
$event->markAsInvalid();
}
return;
}
private function getExpire(): ?string
{
$currentToken = $this->tokenStorage->getToken();
if ($currentToken instanceof JWTPostAuthenticationToken) {
$decodedToken = $this->jwtManager->decode($currentToken);
$expire = time() + $decodedToken['exp'] - $decodedToken['iat'];
return $expire;
}
$data = json_decode($this->getRequestContent()) ?? new \stdClass();
if (! property_exists($data, '_remember_me') || ! $data->_remember_me) {
return null;
}
return (new \DateTimeImmutable('+ ' . self::REMEMBER_ME_TTL))
->getTimestamp();
}
private function getClientIp(): string
{
return $this->requestStack->getCurrentRequest()?->getClientIp() ?? '';
}
private function getRequestContent(): string
{
return $this->requestStack->getCurrentRequest()?->getContent() ?? '';
}
}