Задать вопрос
@EVOSandru6

Почему при тестировании symfony не отрабатывает аутентификатор?

Привет ребят.

Есть аутентификатор для api запросов, который отрабатывает корректно ( юзер из секьюрити формируется ) при CUrl запросах вида:

curl --location --request GET 'http://localhost:8081/api/v1/account/userinfo' \
--header 'Authorization: Bearer %api_token%'


Но в тесте вместо User-а в методе AccountController::getUser прилетает null:

Тест:

class UserinfoTest extends DbWebTestCase
{
    protected EntityManagerInterface $em;
    protected KernelBrowser $client;

    private const API_PREFIX = '/api/v1';

    protected function setUp(): void
    {
        $this->client = static::createClient();
        $this->client->disableReboot();
        $kernel = self::bootKernel();
        DatabasePrimer::prime($kernel);
        $this->em = $kernel->getContainer()->get('doctrine')->getManager();
    }

    public function test_userinfo_success()
    {
        $userRepository = $this->em->getRepository(User::class);
        $testUser = $userRepository->findOneBy(['phone' => '+7 (000) 000-00-01']);

        $token = $testUser->getTokens()[0]->getToken();

        $this->client->request('GET', self::API_PREFIX . '/account/userinfo', [
            'headers' => [
                'Authorization' => 'Bearer ' . $token,
            ],
        ]);
        ...
    }
}


Конфигурация:

security:
  enable_authenticator_manager: true

  password_hashers:
    App\Model\User\Entity\User\User:
      algorithm: 'auto'

  providers:
    app_user_provider:
      entity:
        class: App\Model\User\Entity\User\User
        property: id

  firewalls:
    dev:
      pattern: ^/(_(profiler|wdt)|css|images|js)/
      security: false
    main:
      lazy: true
      provider: app_user_provider
      custom_authenticators:
        - App\Security\Authenticator\ApiTokenAuthenticator
  access_control:


Аутентификатор:

class ApiTokenAuthenticator extends AbstractAuthenticator
{
    public function __construct(
        private ApiTokenRepository $repository
    )
    {
    }

    public function supports(Request $request): ?bool
    {
        $authHeader = $request->headers->get('Authorization');

        return $authHeader && str_starts_with($authHeader, 'Bearer ');
    }

    public function authenticate(Request $request): PassportInterface
    {
        $authHeader = $request->headers->get('Authorization');
        $token = substr($authHeader, 7);

        $apiToken = $this->repository->findOneBy(['token' => $token]) ??
            throw new CustomUserMessageAuthenticationException('Invalid API Token');

        if ($apiToken->isExpired()) {
            throw new CustomUserMessageAuthenticationException('Token expired');
        }

        $user = $apiToken->getUser();

        return new Passport(
            new UserBadge($user->getId()),
            new CustomCredentials(
                fn($credentials, UserInterface $user) => !$credentials->isExpired(),
                $apiToken
            )
        );
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        return null;
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        return new JsonResponse([
            'message' => $exception->getMessageKey()
        ], Response::HTTP_UNAUTHORIZED);
    }
}


Контроллер:

#[Route('api/v1/account')]
class AccountController extends AbstractController
{
    public function __construct(
        private LoggerInterface $logger
    )
    {
    }

    protected function getUser(): User
    {
        return parent::getUser();
    }

    #[Route('/userinfo')]
    public function userInfo(): JsonResponse
    {
        // dump('СЮДА попадаю почему то при тестировании, хотя аутентификатор не должен пускать');

        //  *** При курле все норм ***
        //  !!! При запуске теста поломка, возвращается null вместо User !!!
        $user = $this->getUser();

        $this->logger->warning(json_encode($user));

        return $this->json([
            'code' => 200,
            'data' => [
                'user' => [
                    'username' => (string)$user->getUsername(),
                    'email' => (string)$user->getEmail(),
                    'phone' => (string)$user->getPhone(),
                ]
            ]
        ], 200, []);
    }
}


Мне бы хотелось, чтобы при прилетании заголовка:
Authorization: Bearer ...
Аутентификатор всегда бы отрабатывал
  • Вопрос задан
  • 178 просмотров
Подписаться 1 Простой 2 комментария
Решения вопроса 1
Maksclub
@Maksclub
maksfedorov.ru
Решение

$this->client->request('GET', self::API_PREFIX . '/account/userinfo', [
                'Authorization' => 'Bearer ' . $token,
        ]);


замените на
$this->client->request(
    method: 'GET', 
    uri: self::API_PREFIX . '/account/userinfo',  
    server: ['HTTP_Authorization' => 'Bearer ' . $token,]
);


Пруфы:
https://github.com/symfony/symfony/issues/5074
https://github.com/symfony/browser-kit/blob/5.3/Ab...
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Скорее всего отличаются настройки для тестового и обычного окружения. Разные ключи для генерации токена, или конфиги для подключения к хранилищу с юзерами.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы