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 : https://www.youtube.com/watch?v=XPXrNI-fux4&t=59s 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": "Call to a member function getUser() on null",
    "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 :

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 :

<?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 :

<?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 :

<?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 !

Aucune réponse