<?php
namespace Nen\Bundle\KennisbankPlatformBundle\Security;
use Doctrine\ORM\EntityManagerInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface;
use Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor\QueryParameterTokenExtractor;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use App\Entity\User;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
class JwtTokenAuthenticator extends AbstractAuthenticator
{
private $jwtEncoder;
private $em;
private $urlGenerator;
private $extractor;
public function __construct(JWTEncoderInterface $jwtEncoder, EntityManagerInterface $em, UrlGeneratorInterface $urlGenerator)
{
$this->jwtEncoder = $jwtEncoder;
$this->em = $em;
$this->urlGenerator = $urlGenerator;
$this->extractor = new QueryParameterTokenExtractor(
'jwt'
);
}
public function supports(Request $request): bool
{
return false !== $this->extractor->extract($request) && ! in_array($request->attributes->get('_route'), ['login', 'subscription_index', 'abonnementen_detail']) ;
}
public function getCredentials(Request $request)
{
$token = $this->extractor->extract($request);
if (!$token) {
return;
}
return $token;
}
public function getUser($credentials)
{
try {
$data = $this->jwtEncoder->decode($credentials);
} catch (JWTDecodeFailureException $e) {
// if you want to, use can use $e->getReason() to find out which of the 3 possible things went wrong
// and tweak the message accordingly
// https://github.com/lexik/LexikJWTAuthenticationBundle/blob/05e15967f4dab94c8a75b275692d928a2fbf6d18/Exception/JWTDecodeFailureException.php
throw new CustomUserMessageAuthenticationException('Invalid Token');
}
if ($data === false) {
throw new CustomUserMessageAuthenticationException('Invalid Token');
}
if (empty($data['username'])) {
return null;
}
$username = $data['username'];
return $this->em
->getRepository(User::class)
->findOneBy(['username' => $username]);
}
public function authenticate(Request $request): PassportInterface
{
$credentials = $this->getCredentials($request);
try {
$data = $this->jwtEncoder->decode($credentials);
return new SelfValidatingPassport(
new UserBadge($credentials, [$this, 'getUser'])
);
} catch (JWTDecodeFailureException $e) {
// if you want to, use can use $e->getReason() to find out which of the 3 possible things went wrong
// and tweak the message accordingly
// https://github.com/lexik/LexikJWTAuthenticationBundle/blob/05e15967f4dab94c8a75b275692d928a2fbf6d18/Exception/JWTDecodeFailureException.php
throw new CustomUserMessageAuthenticationException('Invalid Token');
}
return true;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$response = new RedirectResponse($this->urlGenerator->generate('login', ['jwt' => $this->extractor->extract($request)]), 302);
// $response->headers->set('Authorization', 'Bearer ' . $this->extractor->extract($request));
return $response;
// do nothing - let the controller be called
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
return null;
}
public function supportsRememberMe()
{
return false;
}
public function start(Request $request, AuthenticationException $authException = null)
{
return new JsonResponse([
'error' => 'auth required'
], 401);
}
}