Logomark

LARAVEL

Un framework qui rend heureux
Voir cette catégorie
Vers le bas
Voir cette série
Cours Laravel 12 – l’authentification
Vendredi 7 mars 2025 23:54

L’authentification constitue une tâche fréquente. En effet, il y a souvent des parties d’un site qui ne doivent être accessibles qu’à certains utilisateurs, ne serait-ce que l’administration. La solution proposée par Laravel est d’une grande simplicité parce que tout est déjà préparé comme nous allons le voir dans ce chapitre.

Au fil de l'évolution de Laravel, ce domaine a connu bien des fois des changements. Ainsi avec Laravel 6 est apparue une nouveauté. Précédemment il y avait la commande php artisan make:auth pour générer les vues. Cette commande a disparu au profit d'un package à installer (laravel/ui). Mais les changements ont continué, parce qu'ensuite on nous a conseillé d'utiliser un starter kit avec comme choix Breeze ou Jetstream.

Mais ça a encore évolué est nous avons désormais, avec Laravel 12, de nouveaux starter kits. Pour le moment il en existe trois :

  • React
  • Vue
  • Livewire

Mais que vont devenir Breeze et Jetstream ? Comme ils ne seront plus mis à jour, ils vont sans doute sombrer dans l'oubli...

    Quelques principes

    Comment fonctionne l'authentification ?

    L'authentification est un processus essentiel pour sécuriser les applications web. Voici comment elle fonctionne généralement :

    1. Connexion de l'utilisateur : l'utilisateur accède à l'application via un navigateur et saisit ses identifiants (email et mot de passe) dans un formulaire.

    2. Vérification des informations : ces informations sont envoyées au serveur, qui les vérifie par rapport à celles stockées dans la base de données.

    3. Création de la session : si les informations sont correctes, une session est créée pour mémoriser l'authentification. Cette session possède un identifiant unique.

    4. Transmission de l'identifiant : l'identifiant de session est transmis avec chaque requête HTTP, permettant à l'application de reconnaître l'utilisateur sans qu'il ait besoin de se reconnecter à chaque fois.

    5. Authentification des requêtes : lorsqu'une requête HTTP arrive avec un identifiant de session valide, l'application considère l'utilisateur comme authentifié.

    Ce principe ne s'applique pas aux API, car elles ne maintiennent pas de session. À la place, un token est utilisé pour chaque requête afin de vérifier l'identité de l'utilisateur.

    Authentification avec Laravel

    Laravel facilite la mise en place de l'authentification grâce aux façades Auth et Session, qui automatisent la gestion des cookies et offrent de nombreuses méthodes pratiques pour gérer les informations des utilisateurs authentifiés.

    Bien que Laravel fournisse les outils nécessaires pour construire un système d'authentification complet, cette tâche peut être laborieuse. Il est plus simple d'utiliser des starter kits, qui offrent une solution prête à l'emploi.

    Présentation du starter kit de Livewire

    Dans cet article, nous allons explorer l'authentification en utilisant le starter kit de Livewire, qui est particulièrement efficace. Nous aborderons les fonctionnalités suivantes :

    • Enregistrement : comment les utilisateurs peuvent créer un compte.
    • Connexion : le processus de connexion sécurisée.
    • Déconnexion : la gestion de la déconnexion des utilisateurs.
    • Vérification de l'email : assurer que l'adresse email de l'utilisateur est valide.

    En utilisant ce starter kit, vous pourrez mettre en place rapidement un système d'authentification robuste et sécurisé.

    Installation du starter kit

    On va l'installer avec l'installeur CLI de Laravel :

    laravel new laravel12

    On tombe sur une première question :

    Là on choisit livewire. On a ensuite cette question :

    Je parlerai plus tard de WorkOS qui est une alternative intéressante. Pour le moment on choisit la première option laravel.

    On nous demande ensuite quel système de test on veut adopter. Pour le moment ça n'a aucune importance, alors choisissez ce que vous voulez. Vous n'avez plus qu'à attendre la fin de l'installation. Vous avez une dernière question :

    Répondez yes. Et c'est terminé ! Vous arrivez sur la page d'accueil de Laravel mais vous remarquez la présence de deux nouveaux boutons :

    La base de données

    Par défaut la partie persistance de l’authentification (c’est à dire la manière de retrouver les renseignements des utilisateurs) avec Laravel se fait en base de données avec Eloquent et part du principe qu’il y a un modèle App\Models\User. Notez que l'installateur de Laravel génère par défaut une base SQLite.

    Lors de l’installation il existe déjà des migrations :

    On a trois migrations mais on a vu qu'en fait ça va générer huit tables. Parmi ces tables sont concernées par l'authentification :

    • table users : par défaut Laravel considère que cette table existe et il s’en sert comme référence pour l’authentification.
    • table sessions : sert à mémoriser les données de l'utilisateur quand il s'est connecté.
    • table password_reset_tokens : cette table nous servira pour la réinitialisation des mots de passe.

    Les middlewares

    Je vous ai déjà parlé des middlewares qui servent à effectuer un traitement à l’arrivée (ou au départ) des requêtes HTTP. On a vu le middleware de groupe web qui intervient pour toutes les requêtes qui arrivent. Dans ce chapitre on va voir deux autres middlewares qui vont nous permettre de savoir si un utilisateur est authentifié, ou pas, pour agir en conséquence.

    Middleware auth

    Le middleware auth permet de n’autoriser l’accès qu’aux utilisateurs authentifiés, donc de protéger des routes. Ce middleware est déjà présent dans le framework (Illuminate\Auth\Middleware\Authenticate) et son alias est auth.

    On peut utiliser ce middleware directement sur une route :

    Route::get('comptes', function() {
        // Réservé aux utilisateurs authentifiés
    })->middleware('auth');

    Ou un groupe de routes :

    Route::middleware('auth')->group(function () {
        Route::get('/', function ()    {
            // Réservé aux utilisateurs authentifiés
        });
        Route::get('comptes', function () {
            // Réservé aux utilisateurs authentifiés
        });
    });

    Le groupement de routes avec la méthode group permet de mutualiser des actions et de simplifier le code.

    Ou dans le constructeur d’un contrôleur :

    public function __construct()
    {
        $this->middleware('auth');
    }

    Dans ce cas on peut désigner les méthodes concernées avec only ou non concernées avec except :

    public function __construct()
    {
        $this->middleware('auth')->only(['create', 'update']);
    }

    Middleware guest

    Ce middleware est exactement l’inverse du précédent : il permet de n’autoriser l’accès qu’aux utilisateurs non authentifiés. Ce middleware est aussi déjà présent dans le framework avec l'alias guest.

    De la même manière que auth, le middleware guest, comme d'ailleurs tous les middlewares, peut s’utiliser sur une route, un groupe de routes ou dans le constructeur d’un contrôleur, avec la même syntaxe.

    Les routes de l’authentification

    Notre starter kit a généré un nouveau fichier de routes :

    Avec ce code :

    <?php
    
    use App\Http\Controllers\Auth\VerifyEmailController;
    use Illuminate\Support\Facades\Route;
    use Livewire\Volt\Volt;
    
    Route::middleware('guest')->group(function () {
        Volt::route('login', 'auth.login')
            ->name('login');
    
        Volt::route('register', 'auth.register')
            ->name('register');
    
        Volt::route('forgot-password', 'auth.forgot-password')
            ->name('password.request');
    
        Volt::route('reset-password/{token}', 'auth.reset-password')
            ->name('password.reset');
    
    });
    
    Route::middleware('auth')->group(function () {
        Volt::route('verify-email', 'auth.verify-email')
            ->name('verification.notice');
    
        Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
            ->middleware(['signed', 'throttle:6,1'])
            ->name('verification.verify');
    
        Volt::route('confirm-password', 'auth.confirm-password')
            ->name('password.confirm');
    });
    
    Route::post('logout', App\Livewire\Actions\Logout::class)
        ->name('logout');

    Voyons quelles sont les routes générées :

    Il y a beaucoup de routes d'intendance propres à livewire et flux.

    Les vues de l’authentification

    Le starter kit a généré les vues qui servent pour l'authentification :

    Je ne vous montre là que les vues principales, il y en a plusieurs autres : composants, layout, flux...

    Deux remarques concernant ces vues :

    • elles utilisent Volt (que je vous ai présenté dans le précédent article)
    • elles utilisent Flux. C'est une superbe bibliothèque de composant Livewire. Cette bibliothèque est payante, mais elle offre un certain nombre de composants basiques gratuitement (badge, checkbox, button...). Le fait de l'introduire dans ce starter kit est à la fois pratique et gênant. En effet, si on ne veut pas payer pour utiliser d'autres composants que les basiques proposés gratuitement, on est obligé de remanier le code pour avoir une application visuellement homogène.

    L’enregistrement d’un utilisateur

    L'enregistrement d'un utilisateur passe par l'URL .../register. Et cette route :

    Qui envoie sur ce composant Volt :

    Avec cet aspect : 

    Les composant flux (input, button, link) sont assez esthétiques.

    Au moment où je rédige cet article la traduction française n'est pas encore au point, alors je vais rester sur la version anglaise originale.

    La validation

    La validation pour l’enregistrement est présente dans le composant :

    $validated = $this->validate([
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:' . User::class],
        'password' => ['required', 'string', 'confirmed', Rules\Password::defaults()],
    ]);

    De cette manière elle est facile à modifier si vous devez changer des règles ou ajouter un champ.

    On peut vérifier que ça fonctionne :

    La création de l’utilisateur

    La création de l’utilisateur se fait aussi dans le composant :

    public function register(): void
    {
        ...
    
        event(new Registered(($user = User::create($validated))));
    
        Auth::login($user);
    
        ...
    }

    On utilise la méthode create d'Eloquent comme on l'a déjà vu. Vous trouvez dans le modèle App\Models\User.php la propriété $fillable renseignée :

    protected $fillable = [
        'name', 'email', 'password',
    ];

    Donc là encore il est facile d’apporter des modifications si nécessaire.

    Remarquez qu'on génère un événement Registered qui peut servir à lancer une action spécifique lorsqu'un nouvel utilisateur s'enregistre. Je parlerai des événements dans un prochain article.

    Une fois que l’utilisateur est créé dans la base il est automatiquement connecté et est redirigé sur un dashboard :

    Là encore, on a une page qui utilise des composants flux (sidebar, navlist, spacer, dropdown, profile, menu, header...). Prenez le juste comme une suggestion d'organisation.

    La connexion d’un utilisateur

    Pour se connecter, il faut utiliser l'url .../login. Voici la route concernée :

    Si vous venez juste d’enregistrer un utilisateur il faudra le déconnecter avant d’avoir accès au formulaire de login.

    Qui envoie sur ce composant Volt :

    Avec cet aspect :

    On retrouve évidemment les mêmes composants flux pour l'aspect.

    Dans le formulaire de connexion il y a une case à cocher « se rappeler de moi » (remember me) :

    Si on coche cette case on reste connecté indéfiniment jusqu’à ce qu’on se déconnecte intentionnellement. Pour que ça fonctionne il faut une colonne remember_token dans la table users. Il se trouve que cette colonne est prévue dans la migration de base pour la table.

    Le code de la connexion se trouve dans le composant login :

    public function login(): void
    {
        $this->validate();
    
        $this->ensureIsNotRateLimited();
    
        if (! Auth::attempt(['email' => $this->email, 'password' => $this->password], $this->remember)) {
            RateLimiter::hit($this->throttleKey());
    
            throw ValidationException::withMessages([
                'email' => __('auth.failed'),
            ]);
        }
    
        RateLimiter::clear($this->throttleKey());
        Session::regenerate();
    
        $this->redirectIntended(default: route('dashboard', absolute: false), navigate: true);
    }

    Il y a dans ce code un certain nombre de choses intéressantes :

    • Validation : la méthode validate() s'assure que les données d'entrée sont correctes.
    • Rate limiting : ensureIsNotRateLimited() et RateLimiter::hit() sont utilisés pour limiter le nombre de tentatives de connexion afin de prévenir les attaques par force brute.
    • Authentification : Auth::attempt() vérifie les informations d'identification fournies par rapport à celles stockées dans la base de données.
    • Session : Session::regenerate() est utilisé pour régénérer l'ID de session après une connexion réussie, ce qui est une bonne pratique de sécurité.
    • Redirection : redirectIntended() redirige l'utilisateur vers la page qu'il essayait d'accéder avant d'être redirigé vers la page de connexion, ou vers une page par défaut (ici, le tableau de bord).

    La déconnexion d’un utilisateur

    L’utilisateur dispose d’un lien pour se déconnecter sur le tableau de bord :

    Si on clique sur Logout on utilise l'URL .../logout et cette route : 

    Remarquez que la méthode est POST. Du coup la vue (app.sidebar) utilise un formulaire :

    <form method="POST" action="{{ route('logout') }}" class="w-full">
        @csrf
        <flux:menu.item as="button" type="submit" icon="arrow-right-start-on-rectangle" class="w-full">
            {{ __('Log Out') }}
        </flux:menu.item>
    </form>

    C'est une action Livewire qui est appelée :

    Avec ce code :

    public function __invoke()
    {
        Auth::guard('web')->logout();
    
        Session::invalidate();
        Session::regenerateToken();
    
        return redirect('/');
    }

    La vérification de l'email

    Si vous voulez que l'utilisateur confirme son email, et ainsi être sûr que ce n'est pas un fake, il faut que le modèle User implémente l'interface MustVerifyEmail :

    <?php
     
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    
    ...
     
    class User extends Authenticatable implements MustVerifyEmail
    {
        // ...
    }

    On voit du coup une justification de l'événement Registered qui est généré lors de l'inscription d'un nouvel utilisateur.

    Il reçoit ce message lorqu'il s'enregistre :

    Et cet email :

    Lorsqu'il utilise le lien de validation, l'email est bien vérifié, et il est dirigé sur la page de connexion.

    Il ne reste plus qu'à utiliser le middleware verified sur les routes qu'on veut protéger, et qui ne seront donc pas accessible avant la vérification de l'email. Par exemple pour le tableau de bord :

    Route::view('dashboard', 'dashboard')
        ->middleware(['auth', 'verified'])
        ->name('dashboard');

    Il reçoit alors ce message :

    Mais bon... cette vérification de l'email est plutôt illusoire parce que rien n'empêche d'utiliser une adresse temporaire. C'est pour cette raison que je n'utilise jamais cette possibilité qui ajoute de la complexité pour un résultat douteux.

    En résumé

    • L’authentification est totalement et simplement prise en charge par Laravel.
    • Les migrations pour l’authentification sont déjà présentes dans l’installation de base de Laravel.
    • L'utilisation d'un starter kit permet de générer les routes et les composants pour l’authentification.
    • Les middlewares auth et guest permettent d’interdire les accès aux routes qui concernent respectivement les utilisateurs authentifiés ou non authentifiés.


    Par bestmomo

    Nombre de commentaires : 4

    Article précédent : Cours Laravel 12 - Livewire et Volt
    Article suivant : Cours Laravel 12 – l’oubli du mot de passe
    Cet article contient un quiz. Vous devez être authentifié pour y avoir acces.