Как я могу реализовать токен обновления с пользовательской генерацией токена jwt с помощью LexikJWTAuthenticationBundle?

В настоящее время я создаю токен jwt на платформе api с настраиваемым контроллером Symfony, поставщиком и кодирую с помощью JWTEncoderInterface, использую аутентификацию из внешнего API. У меня есть пользователи, но нет пароля в моей базе данных. Как реализовать токен обновления в этой системе?

security.yml

  providers:
        # used to reload user from session & other features (e.g. switch_user)
        user_provider:
            id: App\Security\UserProvider
    firewalls:
        dev:
            pattern: ^/_(profiler|wdt)
            security: false
        api:
            pattern: ^/api/
            stateless: true
            anonymous: true
            provider: user_provider
            guard:
                authenticators:
                    - app.authenticator
        main:
            anonymous: true
            stateless: true
            pattern: /authentication_token

Мой аутентификатор

 <?php

namespace App\Security\Guard;


use Symfony\Component\HttpFoundation\JsonResponse;
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\Guard\AbstractGuardAuthenticator;
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface;

use Throwable;

class Authenticator extends AbstractGuardAuthenticator
{
    private JWTEncoderInterface $jwtEncoder;

    public function __construct(JWTEncoderInterface $jwtEncoder)
    {
        $this->jwtEncoder = $jwtEncoder;
    }

    /**
     * Called on every request to decide if this authenticator should be
     * used for the request. Returning `false` will cause this authenticator
     * to be skipped.
     */
    public function supports(Request $request) : bool
    {
        return $request->headers->has('Authorization Bearer');
    }

    /**
     * Called on every request. Return whatever credentials you want to
     * be passed to getUser() as $credentials.
     */
    public function getCredentials(Request $request) : string
    {
        return $request->headers->get('Authorization Bearer');
    }

    public function getUser($token, UserProviderInterface $userProvider) : UserInterface
    {
        try {
            $user = $this->jwtEncoder->decode($token);
        } catch(Throwable $e) {
            throw new AuthenticationException($e->getMessage());
        }

        return $userProvider->loadUserByUsername($user['email']);
    }

    public function checkCredentials($credentials, UserInterface $user) : bool
    {
        return true;
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        // on success, let the request continue
        return null;
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception) : JsonResponse
    {
        $failure = [
            'message' => $exception->getMessage()
        ];

        return new JsonResponse($failure, Response::HTTP_UNAUTHORIZED);
    }

    /**
     * Called when authentication is needed, but it's not sent
     */
    public function start(Request $request, AuthenticationException $authException = null) : JsonResponse
    {
        $data = [
            'message' => 'Authentication Required'
        ];

        return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
    }

    public function supportsRememberMe() : bool
    {
        return false;
    }
}

Контроллер

#[Route('/authentication_token', name: 'security_authentication_token', methods: ['POST'])]
    public function createAuthenticationToken(
        Request $request,
        CreateTokenAuthenticationHandler $createTokenAuthenticationHandler,
        ValidatorInterface $validator
    ): JsonResponse
    {
        $createTokenAuthentication = CreateTokenAuthentication::createFromPayload($request->request->all());
        $errors = $validator->validate($createTokenAuthentication);

        if (count($errors) > 0) {
            foreach ($errors as $error) {
                $message[]=  sprintf("Field %s: %s ", $error->getPropertyPath(), $error->getMessage());
            }
            return new JsonResponse($message, JsonResponse::HTTP_BAD_REQUEST);
        }

        $token = $createTokenAuthenticationHandler->handle($createTokenAuthentication);

        return new JsonResponse(['token' => $token], JsonResponse::HTTP_OK);
    }

Мой обработчик, в котором я генерирую токен

  public function handle(CreateTokenAuthentication $createTokenAuthentication) : string
    {
        $user = $this->processAuthentication($createTokenAuthentication);

        return $this->jwtEncoder->encode(
            [
                'email' => $user->getEmail(),
                'role' => $user->getRoles()
            ]
        );
    }

Спасибо.

Попробуйте этот пакет github.com/markitosgv/JWTRefreshTokenBundle

michal 07.04.2021 08:43

Спасибо, но в моем случае я генерирую токен только с помощью JWTEncoderInterface, это случай дескриптора библиотеки, в котором используется не лексика, а только его кодировщик? @michal

jikaill 07.04.2021 13:22

Я не знаю ответа на этот вопрос

michal 07.04.2021 13:56

Пакет добавляет к вашему ответу маркер обновления и прослушивает маршрут обновления для выдачи следующего jwt. Если вы хотите сделать это вручную, просто не регистрируйте маршруты и реализуйте свои собственные с расширением встроенного контроллера. Вам также нужно будет сгенерировать refreshtoken при генерации jwt, обычно пакеты делают это при успешной аутентификации в symfony и не прикрепляют токен. Код есть, независимо от того, как вы хотите его использовать, зависит от варианта использования.

Maulik Parmar 08.04.2021 12:40

Спасибо, решите мои вопросы :)

jikaill 08.04.2021 15:44
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
0
5
24
0

Другие вопросы по теме