Bonjour tout le monde,

J'espère que vous allez bien ?

Depuis plusieurs jours, je me bats pour mettre en place l'authentification JWT sur une API construit sous Symfony 5.4 avec APIPlatform et je déprime, car je n'y arrive pas !
J'ai suivi entre autre le tutoriel suivant :
malheureusement cela ne fonctionne pas comme attendu.

La requête api/login fonctionne bien (elle me renvoie un token) sur postman et sur ApiPlatform sauf que sur ApiPlatform, je n'arrive pas à intégrer le "bearerAuth" dans la partie Authorization. Ceci est à mon avis (je peux me tromper) dû à mon autre problème.
Le problème c'est que lorsque je fais appel à ma seconde méthode "api/apiMe" cela me renvoie le message suivant :
{
"@context": "/api/contexts/Error",
"@type": "hydra:Error",
"hydra:title": "An error occurred",
"hydra:description": "Notice: Undefined property: App\\Controller\\ApiMeController::$Security",
"trace": [
{
"namespace": "",
"short_class": "",
"class": "",
"type": "",
"function": "",
"file": "/home/znbf0470/public_html/_dev-erp/src/Controller/ApiMeController.php",
"line": 14,
"args": []
},
{
"namespace": "App\\Controller",
"short_class": "ApiMeController",
"class": "App\\Controller\\ApiMeController",
"type": "->",
"function": "__invoke",
"file": "/home/znbf0470/public_html/_dev-erp/vendor/symfony/http-kernel/HttpKernel.php",
"line": 153,
"args": []
},
{
"namespace": "Symfony\\Component\\HttpKernel",
"short_class": "HttpKernel",
"class": "Symfony\\Component\\HttpKernel\\HttpKernel",
"type": "->",
"function": "handleRaw",
"file": "/home/znbf0470/public_html/_dev-erp/vendor/symfony/http-kernel/HttpKernel.php",
"line": 75,
"args": [
[
"object",
"Symfony\\Component\\HttpFoundation\\Request"
],
[
"integer",
1
]
]
},
{
"namespace": "Symfony\\Component\\HttpKernel",
"short_class": "HttpKernel",
"class": "Symfony\\Component\\HttpKernel\\HttpKernel",
"type": "->",
"function": "handle",
"file": "/home/znbf0470/public_html/_dev-erp/vendor/symfony/http-kernel/Kernel.php",
"line": 202,
"args": [
[
"object",
"Symfony\\Component\\HttpFoundation\\Request"
],
[
"integer",
1
],
[
"boolean",
true
]
]
},
{
"namespace": "Symfony\\Component\\HttpKernel",
"short_class": "Kernel",
"class": "Symfony\\Component\\HttpKernel\\Kernel",
"type": "->",
"function": "handle",
"file": "/home/znbf0470/public_html/_dev-erp/vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php",
"line": 35,
"args": [
[
"object",
"Symfony\\Component\\HttpFoundation\\Request"
]
]
},
{
"namespace": "Symfony\\Component\\Runtime\\Runner\\Symfony",
"short_class": "HttpKernelRunner",
"class": "Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner",
"type": "->",
"function": "run",
"file": "/home/znbf0470/public_html/_dev-erp/vendor/autoload_runtime.php",
"line": 35,
"args": []
},
{
"namespace": "",
"short_class": "",
"class": "",
"type": "",
"function": "require_once",
"file": "/home/znbf0470/public_html/_dev-erp/public/index.php",
"line": 5,
"args": [
[
"string",
"/home/znbf0470/public_html/_dev-erp/vendor/autoload_runtime.php"
]
]
}
]
}

Ci-dessous le code du fichier security.yaml :
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
firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        login:
            pattern: ^/api/login$
            stateless: true
            json_login:
                check_path: /api/login
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure
        main:
            lazy: true
            provider: app_user_provider
            entry_point: App\Security\AppAuthenticator
            custom_authenticator:
                - App\Security\AppAuthenticator
            form_login:
                login_path: app_login
                check_path: app_login
            logout:
                path: app_logout
                target: app_login 
 
        api:
            pattern:   ^/api
            stateless: true
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator
Ci-dessous le code de la class OpenApiFactory :
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
<?php
    namespace App\OpenApi;
 
    use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface;
    use ApiPlatform\OpenApi\OpenApi;
    use ApiPlatform\OpenApi\Model;
 
    class OpenApiFactory implements OpenApiFactoryInterface
    {
        private $decorated;
 
        public function __construct(OpenApiFactoryInterface $decorated)
        {
            $this->decorated = $decorated;
        }
 
        public function __invoke(array $context = []): OpenApi
        {
            $openApi = $this->decorated->__invoke($context);
 
            foreach($openApi->getPaths()->getPaths() as $key => $path) {
                if($path->getGet() && $path->getGet->getSummary() === 'hidden') {
                    $openApi->getPaths()->addPath($key, $path->withGet(null));
                }
            }
 
            $schemas = $openApi->getComponents()->getSecuritySchemes();
            $schemas['bearerAuth'] = new \ArrayObject([
                'type' => 'http',
                'scheme' => 'bearer',
                'bearerFormat' => 'JWT'
            ]);
 
            $schemas = $openApi->getComponents()->getSchemas();
            $schemas['Credentials'] = new \ArrayObject([
                'type' => 'object',
                'properties' => [
                    'username' => [
                        'type' => 'string',
                        'example' => 'john@doe.fr',
                    ],
                    'password' => [
                        'type' => 'string',
                        'example' => 'mdp',
                    ]
                ]
            ]);
            return $openApi;
        }
    }
?>
Ci-dessous le code du controller ApiMeController :
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
<?php
 
namespace App\Controller;
 
use Symfony\Component\Security\Core\Security;
 
class ApiMeController
{
    // private $security;
 
    public function __construct(Security $security){}
 
    public function __invoke() {
        $user = $this->Security->getUser();
        return $user;
    }
}
Ci-dessous le code de l'entité User :
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
<?php
 
namespace App\Entity;
 
use App\Repository\UserRepository;
use App\Controller\ApiMeController;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Serializer\Annotation\Groups;
 
/**
 @ApiResource(
        collectionOperations={
            "apiMe"={
                "pagination_enabled": false,
                "path": "/apiMe",
                "method": "get",
                "controller": ApiMeController::class,
                "read": false,
                "openapi_context"={
                    "security"={"cookieAuth"={}}
                },
            }
        },
       itemOperations={
            "get"={
                "controller": NotFoundAction::class,
                "openapi_context"={
                    "summary":"hidden"
            },
                "read":false,
                "output":false
            },
            "apiMe"={
                "pagination_enabled": false,
                "path": "/apiMe",
                "method": "get",
                "controller": ApiMeController::class,
                "read": false,
                "openapi_context"={
                    "security"={"cookieAuth"={}}
                },
            }

        },
        normalizationContext={"groups"={"user:read"}}
  )
  @ORM\Entity(repositoryClass=UserRepository::class)
  @ORM\Table(name="`user`")
  class User implements UserInterface, PasswordAuthenticatedUserInterface {
  ...
  }
Le problème vient du controller ApiMe. J'ai l'impression que Security ne fonctionne pas.
Ai-je oublié quelque chose ?
Avez-vous une idée pour m'aider à résoudre ce problème s'il vous plaît ?

Merci par avance pour votre aide !