【问题标题】:How to banned a token in LexikJWTAuthenticationBundle?如何在 LexikJWTAuthenticationBundle 中禁止令牌?
【发布时间】:2018-04-25 07:42:28
【问题描述】:

当用户想要退出应用程序时,需要禁止他的令牌,因为它仍然有效。

【问题讨论】:

    标签: symfony jwt symfony4 lexikjwtauthbundle


    【解决方案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。

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 2021-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-17
      • 1970-01-01
      相关资源
      最近更新 更多