<?php
namespace App\Security;
use App\DataProvider\UserInfo\UserInfoItemDataProvider;
use App\Model\Security\UserInfo;
use App\Security\Exception\TokenNotWhitelistedException;
use App\Service\Cache\CacheManager;
use App\V4\Model\Security\UserInfo as UserInfoV4;
use DateTime;
use Exception;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTAuthenticatedEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Security\Guard\JWTTokenAuthenticator;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
/**
* Class JWTAuthenticatedEventListener.
*/
final class JWTAuthenticatedEventListener extends JWTTokenAuthenticator
{
/**
* @var UserInfoItemDataProvider
*/
private $userInfoItemDataProvider;
/**
* @var TokenStorage
*/
private $tokenStorage;
/**
* @var CacheManager
*/
private $cacheManager;
/**
* @var bool
*/
private $enableTokenWhitelist;
/**
* @var string
*/
private $environnement;
/**
* @param UserInfoItemDataProvider $userInfoItemDataProvider
* @param TokenStorage $tokenStorage
* @param CacheManager $cacheManager
* @param bool $enableTokenWhitelist
* @param string|null $environnement
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
*/
public function __construct(
UserInfoItemDataProvider $userInfoItemDataProvider,
TokenStorage $tokenStorage,
CacheManager $cacheManager,
bool $enableTokenWhitelist = false,
string $environnement = null
) {
$this->userInfoItemDataProvider = $userInfoItemDataProvider;
$this->tokenStorage = $tokenStorage;
$this->cacheManager = $cacheManager;
$this->enableTokenWhitelist = $enableTokenWhitelist;
$this->environnement = $environnement;
}
/**
* @param JWTAuthenticatedEvent $event
*
* @return void
*
* @throws Exception
*/
public function onLexikjwtauthenticationOnjwtauthenticated(JWTAuthenticatedEvent $event): void
{
$payload = $event->getPayload();
$this->tokenStorage->setToken($event->getToken());
/**
* Voir : https://gist.github.com/benjaminrau/865f94d142605eb72a23a34ccdd0617a
* As a mechanism to invalidate issued tokes we force token issue date to be higher than a date stored on User::tokenValidAfter
* By updating the User::tokenValidAfter to current date all previously issued tokens become invalid.
*
* Its intended we dont mark as invalid if user isnt found on persistence level because we rely on core JWT
* implementation to handle this case. We want to handle only the validation of tokenValidAfter here.
*
* @var UserInfo User
*/
// Toutes les 5 requêtes, on vérifie que le token de l'utilisateur n'est pas expiré
$current = $this->cacheManager->get(UserInfo::class, 'jwtAuthCheck', $payload['user_id']);
if ($current > 5) {
$current = 0;
$user = $this->userInfoItemDataProvider->getItem(UserInfo::class, $payload['user_id']);
if ($user &&
$user->getTokenValidAfter() instanceof DateTime &&
$payload['iat'] < $user->getTokenValidAfter()->getTimestamp() &&
$this->enableTokenWhitelist
) {
throw new TokenNotWhitelistedException('This token is no longer authorized.');
}
$this->cacheManager->invalidate(UserInfo::class, CacheManager::CACHE_ACTION_KEY_ITEM, null, $payload['user_id']);
$this->cacheManager->invalidate(UserInfoV4::class, CacheManager::CACHE_ACTION_KEY_ITEM, null, $payload['user_id']);
}
$this->cacheManager->set(UserInfo::class, 'jwtAuthCheck', $current + 1, $payload['user_id']);
$this->cacheManager->set(UserInfoV4::class, 'jwtAuthCheck', $current + 1, $payload['user_id']);
}
}