当用户想要退出应用程序时,需要禁止他的令牌,因为它仍然有效。
问问题
1719 次
1 回答
1
这只是我用于我的应用程序的方法
只需为所有或所需路由提供一个新的身份验证器并重写其loadUser
. 我就是这样做的
在 security.yml 中为任何防火墙提供身份验证器
firewalls:
#...
#some firewalls
#...
main:
pattern: ^/
stateless: true
switch_user_stateless: true
guard:
authenticators:
- mylexik_jwt_authentication.security.guard.jwt_token_authenticator
anonymous: false
如您所见,您可以为任何防火墙或所有防火墙定义自己的身份验证器(我这样做)。在这种情况下,我提供的是 lexik 身份验证器的精确副本,但是重新定义了 loadUser 方法(也许可以只重新定义 UserProvider 而不是我不知道的整个身份验证器)。
在 services.yml 中将您的身份验证器注册为服务
mylexik_jwt_authentication.security.guard.jwt_token_authenticator:
class: SeguridadBundle\DependencyInjection\MyJWTTokenAuthenticator
arguments: ["@lexik_jwt_authentication.jwt_manager", "@event_dispatcher", "@lexik_jwt_authentication.extractor.chain_extractor"]
calls:
- [setContainer, ["@service_container"]]
这是我的身份验证器的代码,注意除了 loadUser 方法外完全相同。(更好地扩展JWTTokenAuthenticator
并重新定义 loadUser 方法,更清洁的解决方案)
<?php
namespace SeguridadBundle\DependencyInjection;
use AplicacionBaseBundle\Controller\EmpresaController;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTAuthenticatedEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTExpiredEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTInvalidEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTNotFoundEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Events;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\ExpiredTokenException;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\InvalidPayloadException;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\InvalidTokenException;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTDecodeFailureException;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\MissingTokenException;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\UserNotFoundException;
use Lexik\Bundle\JWTAuthenticationBundle\Response\JWTAuthenticationFailureResponse;
use Lexik\Bundle\JWTAuthenticationBundle\Security\Authentication\Token\JWTUserToken;
use Lexik\Bundle\JWTAuthenticationBundle\Security\Authentication\Token\PreAuthenticationJWTUserToken;
use Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserProvider;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor\TokenExtractorInterface;
use SeguridadBundle\Controller\UsuarioController;
use SeguridadBundle\DependencyInjection\Helpers\GroupHelper;
use SeguridadBundle\DependencyInjection\Helpers\UserHelper;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
/**
* JWTTokenAuthenticator (Guard implementation).
*
* @see http://knpuniversity.com/screencast/symfony-rest4/jwt-guard-authenticator
*
* @author Nicolas Cabot <n.cabot@lexik.fr>
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class MyJWTTokenAuthenticator extends AbstractGuardAuthenticator implements ContainerAwareInterface
{
use ContainerAwareTrait;
/**
* @var JWTTokenManagerInterface
*/
private $jwtManager;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
/**
* @var TokenExtractorInterface
*/
private $tokenExtractor;
/**
* @var TokenStorageInterface
*/
private $preAuthenticationTokenStorage;
/**
* @param JWTTokenManagerInterface $jwtManager
* @param EventDispatcherInterface $dispatcher
* @param TokenExtractorInterface $tokenExtractor
*/
public function __construct(
JWTTokenManagerInterface $jwtManager,
EventDispatcherInterface $dispatcher,
TokenExtractorInterface $tokenExtractor
)
{
$this->jwtManager = $jwtManager;
$this->dispatcher = $dispatcher;
$this->tokenExtractor = $tokenExtractor;
$this->preAuthenticationTokenStorage = new TokenStorage();
}
public function supports(Request $request)
{
return false !== $this->getTokenExtractor()->extract($request);
}
/**
* Returns a decoded JWT token extracted from a request.
*
* {@inheritdoc}
*
* @return PreAuthenticationJWTUserToken
*
* @throws InvalidTokenException If an error occur while decoding the token
* @throws ExpiredTokenException If the request token is expired
*/
public function getCredentials(Request $request)
{
$tokenExtractor = $this->getTokenExtractor();
if (!$tokenExtractor instanceof TokenExtractorInterface) {
throw new \RuntimeException(sprintf('Method "%s::getTokenExtractor()" must return an instance of "%s".', __CLASS__, TokenExtractorInterface::class));
}
if (false === ($jsonWebToken = $tokenExtractor->extract($request))) {
return;
}
$preAuthToken = new PreAuthenticationJWTUserToken($jsonWebToken);
try {
if (!$payload = $this->jwtManager->decode($preAuthToken)) {
throw new InvalidTokenException('Invalid JWT Token');
}
$preAuthToken->setPayload($payload);
} catch (JWTDecodeFailureException $e) {
if (JWTDecodeFailureException::EXPIRED_TOKEN === $e->getReason()) {
throw new ExpiredTokenException();
}
throw new InvalidTokenException('Invalid JWT Token', 0, $e);
}
return $preAuthToken;
}
/**
* Returns an user object loaded from a JWT token.
*
* {@inheritdoc}
*
* @param PreAuthenticationJWTUserToken Implementation of the (Security) TokenInterface
*
* @throws \InvalidArgumentException If preAuthToken is not of the good type
* @throws InvalidPayloadException If the user identity field is not a key of the payload
* @throws UserNotFoundException If no user can be loaded from the given token
*/
public function getUser($preAuthToken, UserProviderInterface $userProvider)
{
if (!$preAuthToken instanceof PreAuthenticationJWTUserToken) {
throw new \InvalidArgumentException(
sprintf('The first argument of the "%s()" method must be an instance of "%s".', __METHOD__, PreAuthenticationJWTUserToken::class)
);
}
$payload = $preAuthToken->getPayload();
$identityField = $this->jwtManager->getUserIdentityField();
if (!isset($payload[$identityField])) {
throw new InvalidPayloadException($identityField);
}
$identity = $payload[$identityField];
try {
$user = $this->loadUser($userProvider, $payload, $identity);
} catch (UsernameNotFoundException $e) {
throw new UserNotFoundException($identityField, $identity);
}
$this->preAuthenticationTokenStorage->setToken($preAuthToken);
return $user;
}
/**
* {@inheritdoc}
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $authException)
{
$response = new JWTAuthenticationFailureResponse($authException->getMessageKey());
if ($authException instanceof ExpiredTokenException) {
$event = new JWTExpiredEvent($authException, $response);
$this->dispatcher->dispatch(Events::JWT_EXPIRED, $event);
} else {
$event = new JWTInvalidEvent($authException, $response);
$this->dispatcher->dispatch(Events::JWT_INVALID, $event);
}
return $event->getResponse();
}
/**
* {@inheritdoc}
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
return;
}
/**
* {@inheritdoc}
*
* @return JWTAuthenticationFailureResponse
*/
public function start(Request $request, AuthenticationException $authException = null)
{
$exception = new MissingTokenException('JWT Token not found', 0, $authException);
$event = new JWTNotFoundEvent($exception, new JWTAuthenticationFailureResponse($exception->getMessageKey()));
$this->dispatcher->dispatch(Events::JWT_NOT_FOUND, $event);
return $event->getResponse();
}
/**
* {@inheritdoc}
*/
public function checkCredentials($credentials, UserInterface $user)
{
return true;
}
/**
* {@inheritdoc}
*
* @throws \RuntimeException If there is no pre-authenticated token previously stored
*/
public function createAuthenticatedToken(UserInterface $user, $providerKey)
{
$preAuthToken = $this->preAuthenticationTokenStorage->getToken();
if (null === $preAuthToken) {
throw new \RuntimeException('Unable to return an authenticated token since there is no pre authentication token.');
}
$authToken = new JWTUserToken($user->getRoles(), $user, $preAuthToken->getCredentials(), $providerKey);
$this->dispatcher->dispatch(Events::JWT_AUTHENTICATED, new JWTAuthenticatedEvent($preAuthToken->getPayload(), $authToken));
$this->preAuthenticationTokenStorage->setToken(null);
return $authToken;
}
/**
* {@inheritdoc}
*/
public function supportsRememberMe()
{
return false;
}
/**
* Gets the token extractor to be used for retrieving a JWT token in the
* current request.
*
* Override this method for adding/removing extractors to the chain one or
* returning a different {@link TokenExtractorInterface} implementation.
*
* @return TokenExtractorInterface
*/
protected function getTokenExtractor()
{
return $this->tokenExtractor;
}
/**
* Loads the user to authenticate.
*
* @param UserProviderInterface $userProvider An user provider
* @param array $payload The token payload
* @param string $identity The key from which to retrieve the user "username"
*
* @return UserInterface
*/
protected function loadUser(UserProviderInterface $userProvider, array $payload, $identity)
{
/*
*Fetch user from database, check if blocked or blacklisted or whatever
*Return the user or false
*
*/
}
}
如果您想检查令牌而不是用户执行上述所有操作,但最后一步并getUser
使用您的自定义逻辑覆盖该方法,而不是如上所述的 loadUser。
希望能帮助到你。
于 2018-04-25T18:15:47.617 回答