Answer the question
In order to leave comments, you need to log in
Why doesn't the authenticator work when symfony tests?
Hey guys.
There is an authenticator for api requests that works correctly (a user from the security is formed) with CUrl requests like:
curl --location --request GET 'http://localhost:8081/api/v1/account/userinfo' \
--header 'Authorization: Bearer %api_token%'
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, []);
}
}
Answer the question
In order to leave comments, you need to log in
Decision
$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,]
);
Most likely, the settings for the test and normal environments are different. Different keys for generating a token, or configs for connecting to a storage with users.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question