Как на symfony добавить возможность аутентификации по JWT токену?

Для добавления возможности аутентификации по JWT токену в Symfony, необходимо выполнить несколько шагов.

Шаг 1: Установка необходимых зависимостей
Для начала, установите необходимые зависимости, такие как lexik/jwt-authentication-bundle и firebase/php-jwt. Выполните следующую команду в корневой директории вашего Symfony проекта:

composer require lexik/jwt-authentication-bundle firebase/php-jwt

Шаг 2: Конфигурация бандла
После установки зависимостей, откройте файл config/bundles.php и добавьте следующую строку:

LexikBundleJWTAuthenticationBundleLexikJWTAuthenticationBundle::class => ['all' => true],

Затем, откройте файл config/packages/lexik_jwt_authentication.yaml и настройте его следующим образом:

lexik_jwt_authentication:
    secret_key: "%env(resolve:APP_SECRET)%"
    public_key: "%env(resolve:JWT_PUBLIC_KEY_PATH)%"
    private_key_passphrase: "%env(JWT_PASSPHRASE)%"
    authentication_header: 'Bearer'
    token_ttl: 3600

Шаг 3: Создание пользовательской аутентификации
Symfony предоставляет инструмент для создания пользовательской аутентификации - UserProvider. Создайте класс src/Security/UserProvider/JwtUserProvider.php и определите его следующим образом:

<?php

namespace AppSecurityUserProvider;

use LexikBundleJWTAuthenticationBundleSecurityUserJWTUserInterface;
use LexikBundleJWTAuthenticationBundleSecurityUserJWTUserProviderInterface;
use SymfonyComponentSecurityCoreExceptionUnsupportedUserException;
use SymfonyComponentSecurityCoreExceptionUserNotFoundException;
use SymfonyComponentSecurityCoreUserUserInterface;

class JwtUserProvider implements JWTUserProviderInterface
{
    public function loadUserByIdentifier(string $identifier): UserInterface
    {
        // реализация загрузки пользователя по идентификатору, например из базы данных
    }

    public function loadUserByUsername(string $username): UserInterface
    {
        // реализация загрузки пользователя по имени пользователя, например из базы данных
    }

    public function loadUserByPayload(array $payload): UserInterface
    {
        // реализация загрузки пользователя по данным токена, например из базы данных
    }

    public function refreshUser(UserInterface $user): UserInterface
    {
        // реализация обновления пользователя, например, проверка данных пользователя
    }

    public function supportsClass(string $class): bool
    {
        $supportedClass = JWTUserInterface::class;

        return $class === $supportedClass || is_subclass_of($class, $supportedClass);
    }
}

Затем, необходимо зарегистрировать этот сервис в config/services.yaml, добавив следующую строку:

services:
    AppSecurityUserProviderJwtUserProvider:
        arguments:
            - '@doctrine'
        tags:
             - { name: lexik_jwt_authentication.user_provider }

Шаг 4: Настройка аутентификации
Откройте файл config/packages/security.yaml и настройте аутентификацию следующим образом:

security:
    encoders:
        AppEntityUser: bcrypt

    providers:
        jwt_user_provider:
            id: AppSecurityUserProviderJwtUserProvider

    firewalls:
        main:
            pattern: ^/
            anonymous: true
            stateless: true
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator

    access_control:
        - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

Шаг 5: Генерация JWT токена
Теперь, вы можете генерировать JWT токен, используя сервис lexik_jwt_authentication.encoder и метод encode:

$encoder = $this->get('lexik_jwt_authentication.encoder');
$token = $encoder->encode(['username' => 'user']);

Шаг 6: Проверка аутентификации
Для проверки аутентификации по JWT токену, вы можете использовать аннотацию @IsGranted в ваших контроллерах, например:

use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentRoutingAnnotationRoute;
use SensioBundleFrameworkExtraBundleConfigurationIsGranted;

class ExampleController extends AbstractController
{
    /**
     * @Route("/example", name="example_route")
     * @IsGranted("ROLE_USER")
     */
    public function exampleAction()
    {
        // реализация действий для аутентифицированного пользователя
    }
}

Это позволит вам ограничить доступ к определенным роутам только для аутентифицированных пользователей с правильной ролью.

Вот и все! Теперь вы имеете возможность аутентифицировать пользователей по JWT токену в Symfony с использованием бандла lexik/jwt-authentication-bundle.