Как забанить токен в LexikJWTAuthenticationBundle? - PullRequest
0 голосов
/ 25 апреля 2018

Когда пользователь хочет выйти из приложения, необходимо забанить свой токен, поскольку он все еще действителен.

1 Ответ

0 голосов
/ 25 апреля 2018

Это просто подход, который я использую для своего приложения.

Просто предоставьте новый аутентификатор для всех или желаемых маршрутов и перепишите его 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 вместо всего аутентификатора, которого я не знаю).

Зарегистрируйте свой аутентификатор какservice в 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, как сказано.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...