Authenticator stateless

Voir la vidéo
Description Sommaire

Dans ce chapitre je vous propose de revenir sur le composant Security et on va découvrir comment créer un système d'authentification stateless pour notre partie API.

Le composant Security est composé de plusieurs éléments :

  • Le UserProvider permet de trouver un utilisateur à partir de son identifier.
  • L'Authenticator qui lui se charge d'authentifier l'utilisateur lors de certaines requête.

Dans le cadre d'une API, on aura en général une entête particulière Authorization qui nous permet d'identifier l'utilisateur qui est à l'origine de la requête.

<?php

namespace App\Security;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;

class APIAuthenticator extends AbstractAuthenticator
{

    public function supports(Request $request): ?bool
    {
        return $request->headers->has('Authorization') && str_contains($request->headers->get('Authorization'), 'Bearer ');
    }

    public function authenticate(Request $request): Passport
    {
        $identifier = str_replace('Bearer ', '', $request->headers->get('Authorization'));
        return new SelfValidatingPassport(
            new UserBadge($identifier)
        );
    }

    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->getMessage()
        ], Response::HTTP_UNAUTHORIZED);
    }
}

Dans notre cas, on crée un passeport qui contient comme identifier la clef d'API. Il faudra ensuite modifier la configuration pour ajouter cet authenticator sur les URLs qui commencent par /api.

security:
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
    providers:
        api_user_provider:
            entity:
                class: App\Entity\User
                property: apiToken
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        api:
            pattern: ^/api/
            provider: api_user_provider
            custom_authenticator: App\Security\APIAuthenticator
            stateless: true
            lazy: true

Dans mon cas, je me contente de chercher l'utilisateur qui a la propriété apiToken qui correspond à la clef d'authorization. Pour des cas plus complexes, vous pouvez utiliser un provider personnalisé.

Publié
Technologies utilisées
Auteur :
Grafikart
Partager