Bonjour,
Je suis sous symfony 7.1 et php 8.2, j'essaye de mettre en place la gestion de token lors d'appel de mon api.
Comme dans le tuto de Grafikart je me retrouve avec une class TokenAuthenticator dans le dossier Security, je rentre bien dans la méthode authenticate, mais j'ai un souci de typage de mon $jwt pour le décode $payload = $this->jwtTokenManager->decode($jwt); Visiblement, il devrait être de type TokenInterface. Mais je n'arrive pas à le faire.

Quelque chose m'échappe, peut-être que je m'y prends mal.

J'aurais pu utiliser la méthode parse(), mais j'ai cru comprendre que c'est mieux d'avoir un objet de type tokenInterface afin de bénéficier de toute la mécanique de symfony, notamment la gestion des rôles avec les URL.

Quelqu'un aurait une idée ?

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<?php
 
namespace App\Security;
 
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTDecodeFailureException;
use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Lexik\Bundle\JWTAuthenticationBundle\Security\Authentication\Token\PreAuthenticatedJWTUserToken;
 
class TokenAuthenticator extends AbstractAuthenticator
{
    private $logger;
    private $userProvider;
    private $publicKeyPath;
    private $jwtTokenManager;
 
    public function __construct(
        LoggerInterface $logger,
        UserProviderInterface $userProvider,
        string $publicKeyPath,
        JWTTokenManagerInterface $jwtTokenManager
    ) {
        $this->logger = $logger;
        $this->userProvider = $userProvider;
        $this->publicKeyPath = $publicKeyPath;
        $this->jwtTokenManager = $jwtTokenManager;
    }
 
    public function supports(Request $request): ?bool
    {
        // Log all headers for debugging
        $headers = $request->headers->all();
        $this->logger->info('Request headers', $headers);
 
        $authHeader = $request->headers->get('Authorization');
        if ($authHeader === null || strpos($authHeader, 'Bearer ') !== 0) {
            $this->logger->info('Authorization header missing or incorrect');
            return false;
        }
        $this->logger->info('Authorization header found and correct');
        return true;
    }
 
 public function authenticate(Request $request): Passport
{
    $authHeader = $request->headers->get('Authorization');
    if (!$authHeader || !str_starts_with($authHeader, 'Bearer ')) {
        throw new AuthenticationException('No Bearer token found');
    }
 
    $jwt = str_replace('Bearer ', '', $authHeader);
    $this->logger->info('JWT Token: ' . $jwt);
 
    try {
        // Utiliser JWTTokenManagerInterface pour décoder le token
        $payload = $this->jwtTokenManager->decode($jwt);
    } catch (JWTDecodeFailureException $e) {
        throw new AuthenticationException('Invalid JWT token');
    }
 
    // Vérification de l'expiration
    if (isset($payload['exp']) && $payload['exp'] < time()) {
        throw new AuthenticationException('Token has expired');
    }
 
    if (!is_array($payload) || !isset($payload['username'])) {
        throw new AuthenticationException('Invalid JWT payload');
    }
 
    $userIdentifier = $payload['username'];
 
    return new SelfValidatingPassport(
        new UserBadge($userIdentifier, function ($userIdentifier) {
            $user = $this->userProvider->loadUserByIdentifier($userIdentifier);
 
            // Logging des rôles de l'utilisateur
            $roles = implode(', ', $user->getRoles());
            $this->logger->info('User roles: ' . $roles);
 
            return $user;
        })
    );
}
 
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        $this->logger->info('Authentication successful');
        return null;
    }
 
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        $this->logger->warning('Authentication failed: ' . $exception->getMessage());
        return new JsonResponse(['message' => $exception->getMessage()], Response::HTTP_UNAUTHORIZED);
    }
}