Как в Symfony 4.3 принудительно разлогинить юзера по ID?

В Symfony 4.3 можно принудительно разлогинить пользователя по его идентификатору (ID) с помощью класса TokenProviderInterface и сервиса security.token_storage. Вот как это сделать:

1. Сначала необходимо создать сервис, который будет использоваться для разлогинивания пользователя. Для этого создаем новый класс, например, ForceLogoutService.

// src/Service/ForceLogoutService.php

namespace AppService;

use SymfonyComponentSecurityCoreAuthenticationTokenStorageTokenStorageInterface;
use SymfonyComponentSecurityCoreExceptionAuthenticationException;
use SymfonyComponentSecurityCoreExceptionLogoutException;
use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;
use SymfonyComponentSecurityCoreAuthenticationTokenUsernamePasswordToken;
use SymfonyComponentSecurityCoreAuthenticationTokenPreAuthenticatedToken;

class ForceLogoutService
{
    private $tokenStorage;

    public function __construct(TokenStorageInterface $tokenStorage)
    {
        $this->tokenStorage = $tokenStorage;
    }

    public function logoutUserById(int $userId): void
    {
        // Получаем текущий токен пользователя
        $currentToken = $this->tokenStorage->getToken();

        if (!$currentToken instanceof UsernamePasswordToken && !$currentToken instanceof PreAuthenticatedToken) {
            throw new AuthenticationException('Invalid token type.');
        }

        // Проверяем, совпадает ли ID пользователя с переданным ID
        $user = $currentToken->getUser();
        if ($user instanceof UserInterface && $user->getId() === $userId) {
            // Удаляем токен из хранилища
            $this->tokenStorage->setToken(null);
            
            // Генерируем исключение для принудительного разлогинивания
            throw new LogoutException('Force logout.');
        }
    }
}

2. Затем необходимо зарегистрировать этот сервис в контейнере зависимостей Symfony. Для этого открываем файл services.yaml в директории config и добавляем следующую строчку:

# config/services.yaml

AppServiceForceLogoutService:
    arguments:
        - '@security.token_storage'

3. Теперь мы можем использовать сервис ForceLogoutService для разлогинивания пользователя по его ID. В контроллере или другом месте приложения, где необходимо разлогинить пользователя, добавляем инъекцию зависимости сервиса:

// src/Controller/YourController.php

namespace AppController;

use AppServiceForceLogoutService;
use SymfonyComponentRoutingAnnotationRoute;

class YourController extends AbstractController
{
    private $forceLogoutService;

    public function __construct(ForceLogoutService $forceLogoutService)
    {
        $this->forceLogoutService = $forceLogoutService;
    }

    /**
     * @Route("/logout/{userId}", name="logout_by_id")
     */
    public function logoutById(int $userId)
    {
        $this->forceLogoutService->logoutUserById($userId);

        // Редирект или другие действия после разлогинивания пользователя
    }
}

Теперь, когда пользователь обращается по пути /logout/{userId}, сервис ForceLogoutService проверяет, совпадает ли переданный ID с текущим пользователем. Если да, то происходит принудительное разлогинивание пользователя.