4 - Un peu de sécurité
Une fois le modèle définis, il est désormais assez simple de créer les API selon le cahier des charges.
Le plus dur est de correctement la sécurisé, c'est cependant grandement simplifié avec Symfony et son composant de sécurité.
Une fois de plus, leur doc est un très bon point d'entré:
Souvent ce bundle: https://symfony.com/bundles/LexikJWTAuthenticationBundle/current/index.html est utilisé pour gérer l'authentification via API. Cependant il est souvent mal compris, et il n'est pas difficile de créer son propre système.
Si vous souhaitez mieux comprendre comment fonctionne un JWT: https://www.vaadata.com/blog/fr/jetons-jwt-et-securite-principes-et-cas-dutilisation/
Gérer soit même la sécurité
Tout commence par l'installation du composant Symfony:
Une fois ces deux packages installés, on peut commencer le code.
Si vous n'avez pas d'entity User, vous pouvez la créer avec une commande du maker:
Cette commande ne fait simplement que de générer une entité en lui ajoutant deux interfaces requises par le composant Security de symfony et en implémentant toutes les méthodes par défaut:
Notre classe utilisateur est prête à être utiliser par la sécurité Symfony.
La commande make:user édite normalement la configuration du fichier de sécurité, pour lui dire que lorsque notre app aura besoin de charger un utilisateur, il se basera sur cette entité.
C'est toujours bien d'aller jeter un coup d'oeil au cas où.
Le provider défini comment (re)charger des utilisateurs depuis un stockage en fonction d'un "UserIdentifier".
Ici on utilise l'entityUserProvider de base fournis par symfony. On lui précise que l'entity à check est App\Entity\User et que la propiété qui sert de "UserIdentifier" est l'email.
Pour la suite on supposera que vous avez déjà des utilisateurs en base, et que vous connaissez le couple email/password d'un compte. (vous pouvez faire une Command de création d'user par exemple)
Comme pour le JWT, on souhaite faire un système d'auth via un Token. Il sera donc en 2 parties:
Authentification via email/password pour récupérer notre Token
Authentification via notre Token
Récupérer un token
Une fois de plus, Symfony fait quasiment tout pour nous et nous propose un JSON login authenticator, exactement ce qu'il nous faut pour notre API.
Pour l'utiliser c'est très simple, il nous suffit d'ajouter un nouveau Firewall dans notre fichier de config de la sécurité:
Les firewall dev et main sont présent par défaut avec Symfony, nous nous plaçons simplement entre les deux.
Ici la config est plutôt simple:
api_login: le nom de notre nouveau firewallpattern: le pattern que l'url doit avoir pour que ce firewall s'applique (ici, l'url doit forcément être "/api/login")stateless: cela signifie que les informations des sessions ouvertes ne sont pas stockées côté serveur (contrairement au sessions/cookie)provider: le provider configuré plus tôt, pour indiquer à symfony comment charger notre utilisateurjson_login.check_path: le nom de la route lié à notre authenticatorjson_login.username_path: customisation de la requête d'authentification pour lui dire qu'on veut envoyer un "email" dans notre requête JSON
Désormais nous devons créer notre controller:
Ce contrôleur de connexion sera appelé après que l'authenticator de Symfony ait authentifié l'utilisateur avec succès. Vous pouvez récupérer l'utilisateur authentifié, générer un token et renvoyer une réponse JSON
⚠️ La config de votre attribut #[Route] doit suivre la config de votre firewall (l'url === la clé pattern, le name === la clé check_path)
Désormais si vous appelez /api/login avec les identifiants correct, vous devriez obtenir votre-super-token:
Nous devons maintenant générer un vrai token sécurisé.
Pour ce faire voici un exemple de service qui peut encoder/decoder un token:
Ce service va venir créer un token sécurisé qui stock l'email de notre utilisateur via la fonction generateTokenForUser, c'est cette fonction que nous devrions utiliser dans notre LoginController pour récupérer le token et ainsi pouvoir s'authentifier dans le reste de l'API.
Authentification via notre token
Pour nous authentifer via notre Token, nous allons créer un Authenticator custom côté Symfony.
Pour cela, le concept de base est le même: on ajoute un firewall dans notre config.
Toujours le même schéma:
pattern: le pattern que l'url doit avoir pour que ce firewall s'applique (ici, l'url doit forcément commencé par "/api/")stateless: cela signifie que les informations des sessions ouvertes ne sont pas stockées côté serveur (contrairement au sessions/cookie)provider: le provider configuré plus tôt, pour indiquer à symfony comment charger notre utilisateurcustom_authenticators: l'autenthicator custom que nous allons utilisé pour checker si notre token est valide ou non.
L'ordre des firewalls est important ! Seul le premier match sera analysé
Nous devons maintenant créer l'authenticator qui sera chargé de checker à chaque requête commencant par /api si le token fournis est valide et donc nous connecter à l'API / nous refuser l'accès
En bref, cet authenticator vérifie que notre requête courante à bien un header Authorization.
Si la requête à bien ce header, nous passerons dans la méthode authenticate qui sera chargé de vérifier le token fournis dans le header. Si il est valide, il nous retourne l'utilisateur lié à ce token, sinon il ne renverra rien.
Enfin, si l'auth ne fonctionne pas (dans le cas ou la méthode authenticate ne trouve pas d'utilisateur) , on passe dans la méthode onAuthenticationFailure qui se charge de renvoyer une réponse d'erreur et mets fin au process.
Toutes vos Api créer précédemment sont donc limité aux utilisateurs sans plus d'actions de votre part.
La suite est d'accorder de la granularité aux données visibles selon l'utilisateur connecté.
Last updated
