Created
July 12, 2017 09:17
-
-
Save matthbull/8ab0a3b8e3ada525ecae3c733668afee to your computer and use it in GitHub Desktop.
JWTGuard authenticator - symfony 3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Date: 07/04/17 | |
* Time: 09:51 | |
*/ | |
namespace AppBundle\Security; | |
use AppBundle\Api\ResponseFactory; | |
use AppBundle\Exception\ApiProblem; | |
use AppBundle\Services\LoggerAwareInterface; | |
use AppBundle\Traits\LoggerAwareTrait; | |
use Doctrine\ORM\EntityManager; | |
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface; | |
use Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor\AuthorizationHeaderTokenExtractor; | |
use Monolog\Logger; | |
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\Exception\CustomUserMessageAuthenticationException; | |
use Symfony\Component\Security\Core\User\UserInterface; | |
use Symfony\Component\Security\Core\User\UserProviderInterface; | |
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator; | |
/** | |
* | |
* Class JwtTokenAuthenticator | |
* | |
* This is a guard class, specified in security.yml. It only looks for tokens and then decodes it to get the user. | |
* JWT tokens use the jwt private and public keys in /var/jwt to ensure that the token hasnt been tampered with. | |
* So whilst its easy to decode them, a hacker cant change them. This provides an adequate security layer. | |
* | |
* @file security.yml | |
* | |
* | |
* @package AppBundle\Security | |
* @author: Matt Holbrook-Bull <matt@ampisoft.com> | |
*/ | |
class JwtTokenAuthenticator extends AbstractGuardAuthenticator implements LoggerAwareInterface | |
{ | |
use LoggerAwareTrait; | |
/** | |
* @var JWTEncoderInterface | |
*/ | |
private $encoder; | |
/** | |
* @var EntityManager | |
*/ | |
private $em; | |
/** | |
* @var ResponseFactory | |
*/ | |
private $responseFactory; | |
/** | |
* JwtTokenAuthenticator constructor. | |
* | |
* @param JWTEncoderInterface $encoder | |
* @param EntityManager $em | |
* @param ResponseFactory $responseFactory | |
*/ | |
public function __construct(JWTEncoderInterface $encoder, EntityManager $em, ResponseFactory $responseFactory) | |
{ | |
$this->encoder = $encoder; | |
$this->em = $em; | |
$this->responseFactory = $responseFactory; | |
} | |
/** | |
* @param Request $request | |
* @return array|bool|false|null|string | |
*/ | |
public function getCredentials(Request $request) | |
{ | |
// get the token information and return it | |
$extractor = new AuthorizationHeaderTokenExtractor( | |
'Bearer', | |
'Authorization'); | |
$token = $extractor->extract($request); | |
if(!$token) { | |
// only log for closed endpoints | |
if(strpos($request->getUri(), '/login/app-login.php') === false) { | |
$this->logger->log(Logger::DEBUG, | |
sprintf('[API FIREWALL] No token detected trying to access: %s from IP: %s',$request->getUri(), $request->getClientIp())); | |
} | |
return null; | |
} | |
return $token; | |
} | |
/** | |
* @param mixed $credentials | |
* @param UserProviderInterface $userProvider | |
* @return \AppBundle\Entity\Player|null|object | |
*/ | |
public function getUser($credentials, UserProviderInterface $userProvider) | |
{ | |
$creds = $this->encoder->decode($credentials); | |
if(!$creds) { | |
throw new CustomUserMessageAuthenticationException('Invalid token'); | |
} | |
return $this->em->getRepository('AppBundle:Player') | |
->findOneBy(['username' => $creds['username']]); | |
} | |
/** | |
* @param mixed $credentials | |
* @param UserInterface $user | |
* @return bool | |
*/ | |
public function checkCredentials($credentials, UserInterface $user) | |
{ | |
return true; | |
} | |
/** | |
* @param Request $request | |
* @param AuthenticationException $exception | |
* @return null|Response|void | |
*/ | |
public function onAuthenticationFailure(Request $request, AuthenticationException $exception) | |
{ | |
} | |
/** | |
* @param Request $request | |
* @param TokenInterface $token | |
* @param string $providerKey | |
* @return null|Response|void | |
*/ | |
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) | |
{ | |
// do nothing | |
} | |
/** | |
* @return bool | |
*/ | |
public function supportsRememberMe() | |
{ | |
return false; | |
} | |
/** | |
* Entry point is only used if all else fails. | |
* | |
* @param Request $request | |
* @param AuthenticationException|null $authException | |
* @return \Symfony\Component\HttpFoundation\JsonResponse | |
*/ | |
public function start(Request $request, AuthenticationException $authException = null) | |
{ | |
// return a failed response type | |
$apiProblem = new ApiProblem(401); | |
$message = $authException ? $authException->getMessageKey() : 'Missing credentials'; | |
$apiProblem->set('detail', $message); | |
$this->logger->error($apiProblem->get('detail')); | |
return $this->responseFactory->createResponse($apiProblem); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment