Joel MPIANA ECHIKUNWOKE
5 min readJan 19, 2023

Authentification JWT Symfony 6

La version 6 de Symfony vient avec un bon nombre de changements parmi lesquels la structure de l’entité User et l’exclusivité de la version 8 de Php.

Une grande démarcation avec la version 5 qui va impacter la configuration du JWT pour l’authentification.

Dans l’entité User, la fonction getUsername(), identifiant visuel qui représente cet utilisateur, jusqu’ici présente dans la version 5 de Symfony est remplacé par getUserIdentifier(). Changement qui va modifier les entrées ou en têtes du JWT dans le fichier security.yaml

Configuration

  1. Prérequis

Pour ce projet, voici les prérequis:

Composer, PHP 8, XAMPP et un éditeur de texte.

2. Installation et configuration

Nous allons commencer par installer un projet symfony de type api.

Dans la console : symfony new my-api

Rendez vous ensuite dans la racine du projet et ouvrez le dans un éditeur de texte.

Nous allons utiliser Visual Studio Code.

Nous allons installer un certain nombre de librairies(Bundles).

composer require symfony/orm-pack(pour la gestion de la base de données)

composer require — dev symfony/maker-bundle(permettre

de gérer nos entités, contrôleurs, autres commandes..)

Dans le fichier .env, choisir un type de base de données.

Nous travaillerons avec Mysql

DATABASE_URL=”mysql://root:@127.0.0.1:3306/api_db? serverVersion=8&charset=utf8mb4"

Installer ensuite les bundles :

composer require security:

pour configurer les accès à notre application dans le fichier config/packages/security.yaml)

composer require annotation:

pour pouvoir écrire nos routes dans le contrôleur)

composer require twig

composer require profiler(pour le debug de notre application)

composer require serializer(pour sérialisé nos données )

Créons l’entité User

Symfony console make:User

* A visual identifier that represents this user.

*

* @see UserInterface

*/

public function getUserIdentifier(): string

{

return (string) $this->email;

}

Nous pouvons voir la nouvelle configuration de l’entité User qui fera toute la différence dans la suite.

Nous pouvons maintenant installer notre bundle JWT

Principe

Dans la console: composer require lexik/jwt-authentication-bundle

Le fichier config/packages/lexik_jwt_authentification.yaml sera créé.

Nous avons configuré le temps de validité du token.

Création des publiques et privées

Avant de passer à cette étape, dans le fichier .env, nous modifions le champ JWT_PASSPHRASE du fait que nous allons créer nos clés manuellement.

Dans la console, nous exécutons les commandes suivantes. La console dans les deux cas nous demandera de saisir la phrase secrète.

$ mkdir config/jwt

$ openssl genrsa -out config/jwt/private.pem -aes256 4096

$ openssl rsa -pubout -in config/jwt/private.pem -out config/jwt/public.pem

Configuration du fichier security.yaml

On notera trois choses dans ce fichier:

Le hachage du mot pass: Nous laisserons plaintext pour ne pas avoir un hachage

le provider : ça sera l’entité user via l’email.

l’implémentation du jwt:

login:

pattern: ^/api/login

stateless: true

provider: app_user_provider

json_login:

check_path: /api/login_check

username_path: email

password_path: password

success_handler: lexik_jwt_authentication.handler.authentication_success

failure_handler: lexik_jwt_authentication.handler.authentication_failure

api:

pattern: ^/api

stateless: true

jwt: ~

Contrairement aux versions précédentes, deux champs seront ajoutés.

username_path: email

password_path: password

Ceci suite à la modification de l’entité User.

Ensuite ajouter la route dans le fichier routes.yaml

api_login_check:

path: /api/login_check

Avec ceci, notre configuration du bundle JWT se termine.

le fichier final security.yaml sera :

security:

enable_authenticator_manager: true

# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords

password_hashers:

App\Entity\User:

algorithm: plaintext

encode_as_base64: false

iterations: 1

# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider

providers:

# used to reload user from session & other features (e.g. switch_user)

app_user_provider:

entity:

class: App\Entity\User

property: email

firewalls:

dev:

pattern: ^/(_(profiler|wdt)|css|images|js)/

security: false

login:

pattern: ^/api/login

stateless: true

provider: app_user_provider

json_login:

check_path: /api/login_check

username_path: email

password_path: password

success_handler: lexik_jwt_authentication.handler.authentication_success

failure_handler: lexik_jwt_authentication.handler.authentication_failure

api:

pattern: ^/api

stateless: true

jwt: ~

# activate different ways to authenticate

# https://symfony.com/doc/current/security.html#the-firewall

# https://symfony.com/doc/current/security/impersonating_user.html

# switch_user: true

# Easy way to control access for large sections of your site

# Note: Only the *first* access control that matches will be used

access_control:

- { path: ^/api/login, roles: PUBLIC_ACCESS }

- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

when@test:

security:

password_hashers:

# By default, password hashers are resource intensive and take time. This is

# important to generate secure password hashes. In tests however, secure hashes

# are not important, waste resources and increase test times. The following

# reduces the work factor to the lowest possible values.

Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:

algorithm: plaintext

cost: 4 # Lowest possible value for bcrypt

time_cost: 3 # Lowest possible value for argon

memory_cost: 10 # Lowest possible value for argon

Test de configuration

Pour ce faire nous allons créer un utilisateur.

Générons un contrôleur dans la console: symfony console make:controller UserController

Nous utiliserons le manager pour communiquer avec la base de données, l’injection de dépendances pour l’entité User.

Nous allons hacher le mot de passe pour le besoin du test.

Notre contrôleur sera comme suivant:

<?php

namespace App\Controller;

use App\Entity\User;

use App\Repository\UserRepository;

use Doctrine\ORM\EntityManagerInterface;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

use Symfony\Component\HttpFoundation\JsonResponse;

use Symfony\Component\HttpFoundation\Request;

use Symfony\Component\HttpFoundation\Response;

use Symfony\Component\Routing\Annotation\Route;

class UserController extends AbstractController

{

public function __construct(EntityManagerInterface $manager, UserRepository $userRepository)

{

$this->em=$manager;

$this->user=$userRepository;

}

//Création d’un utilisateur

#[Route(‘/userCreate’, name: ‘user_create’, methods:’POST’)]

public function userCreate(Request $request): Response

{

$data=json_decode($request->getContent(),true);

$email=$data[“email”];

$password=$data[“password”];

//Vérification de l’email

$checkEmail=$this->user->findOneByEmail($email);

if($checkEmail)

{

return new JsonResponse([

“status”=>false,

“message”=>”Cet email existe déjà, vous pouvez choisir un autre !”

]);

}

else

//Création d’un nouvel utilisateur

$user= new User();

$user->setEmail($email)

->setPassword(sha1($password));

$this->em->persist($user);

$this->em->flush();

return new JsonResponse([

“status”=>true,

“message”=>”L’utilisateur a été créé avec succès !”

]);

}

}

Nous utliserons Talend API Tester pour tester notre api

Démarrons notre projet : symfony serve

Notre utilisateur a bien été créé.

Nous pouvons le voir dans la base de données.

Nous testons enfin notre authentification

Le token est bien généré et peut être utilisé par un client front pour accorder ou restreindre l’accès aux utilisateurs.

Conclusion

Nous avons voulu à travers cet article implémenter un mode d’authentification sous symfony entre autres le JWT(JSON WEB TOKEN).

Nous avons parcouru divers étapes en notant les changements dus à la version récente de Symfony.

Cet article peut davantage être enrichi avec plusieurs features, nous avons abordé la base de l’architecture.

Bonne lecture.

Joel MPIANA ECHIKUNWOKE
0 Followers

Software Developer, Technical Writer and Entrepreneur