<?php
declare(strict_types=1);
namespace App\Listener\JWT;
use App\Exception\Auth\AuthenticationFailedException;
use App\Exception\User\UserAccountLoginNotAllowedException;
use App\Exception\User\UserAccountNotFoundException;
use App\Exception\User\UserPasswordInvalid;
use App\Tool\Encryption\JWTDecoder;
use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationFailureEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\MissingTokenException;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
class AuthenticationFailureListener
{
private array $customExceptions = [UserAccountLoginNotAllowedException::class, UserAccountNotFoundException::class];
public function onAuthenticationFailure(AuthenticationFailureEvent $event): void
{
$additionalInfo = [];
$exception = $event->getException();
if (!$exception instanceof MissingTokenException) {
$jwtToken = $event->getRequest()->headers->get('authorization');
if (!empty($jwtToken)){
$decodedJwtToken = JWTDecoder::decode($jwtToken);
if(is_array($decodedJwtToken)) {
$additionalInfo = [
'userId' => array_key_exists('id', $decodedJwtToken) ? $decodedJwtToken['id'] : '',
'username' => array_key_exists('username', $decodedJwtToken) ? $decodedJwtToken['username'] : ''
];
}
}
}
$nestedException = $exception ? $exception->getPrevious() : $exception;
if ($nestedException instanceof BadCredentialsException) {
throw new UserPasswordInvalid();
}
if ($this->isCustomException($nestedException)){
throw $nestedException;
}
throw new AuthenticationFailedException($additionalInfo);
}
private function isCustomException(?\Exception $exception): bool
{
return $exception && in_array(get_class($exception), $this->customExceptions, true);
}
}