Laravel 9

Cours Laravel 9 – la sécurité – Jetstream

On a vu précédemment l’utilisation de Breeze pour installer un système complet d’authentification. Il existe un deuxième starter kit dans Laravel, il s’agit de Jetstream. Celui-ci reprend toutes les fonctionnalités de Breeze et en ajoute d’autres : authentification à deux facteurs, gestion des sessions, et possibilité de gérer des équipes. Nous allons voir dans cet article comment l’installer et l’utiliser.

Les routes de l’authentification

Dans l’installation de base vous ne trouvez aucune route pour l’authentification. Pour les créer (et ça ne créera pas seulement les routes) il faut déjà installer Jetstream :

composer require laravel/jetstream

Ensuite on a le choix entre Livewire (avec Blade) et Inertia (avec Vue.js) selon les goûts ou habitudes. Pour ce cours je vais utiliser Livewire qui a un grand succès dans la communauté.

php artisan jetstream:install livewire
npm install
npm run dev
php artisan migrate

Ça prend un peu de temps parce qu’il y a pas mal de chose à faire. Je parlerai de cet aspect dans un article ultérieur.

Pendant ce temps regardez ce qui a été ajouté dans le fichier routes/web.php :

Route::middleware(['auth:sanctum', 'verified'])->get('/dashboard', function () {
    return view('dashboard');
})->name('dashboard');

Voyons quelles sont les routes générées (vous devez maintenant bien connaître la commande correspondante d’Artisan :

Vous voyez qu’on a produit pas mal de routes mais elles ne servent pas toutes pour l’authentification !

Une autre chose intéressante aussi est la création d’un dossier pour les actions de Fortify et Jetstream :

En ce qui concerne la base de données vous pouvez avoir un aperçu précis dans DrawSQL.

Nous allons voir bientôt tout ça en action.

Les vues de l’authentification

Il y a également eu la génération de nombreuses vues :

On va aussi voir à quoi servent toutes ces vues. Elles ne sont pas toutes utilisées par l’authentification.

L’enregistrement d’un utilisateur

Commençons par le commencement avec l’enregistrement d’un utilisateur. Si vous allez sur la page d’accueil vous allez remarquer la présence en haut à droite de la page de deux liens :

On trouve ce code dans la page d’accueil :

@if (Route::has('login'))
    <div class="hidden fixed top-0 right-0 px-6 py-4 sm:block">
        @auth
            <a href="{{ url('/dashboard') }}" class="text-sm text-gray-700 dark:text-gray-500 underline">Dashboard</a>
        @else
            <a href="{{ route('login') }}" class="text-sm text-gray-700 dark:text-gray-500 underline">Log in</a>

            @if (Route::has('register'))
                <a href="{{ route('register') }}" class="ml-4 text-sm text-gray-700 dark:text-gray-500 underline">Register</a>
            @endif
        @endauth
    </div>
@endif

On en profite pour voir les opérateurs conditionnels de Blade.

Avec un @if on vérifie si dans les routes (Route) on a (has) une route login et si c’est le cas on vérifie si l’utilisateur est authentifié avec @auth, si c’est le cas on affiche un lien vers le dashboard et si ce n’est pas le cas (@else) on affiche les deux liens de l’authentification.

Si on clique sur Register on appelle une méthode de Fortify :

Remarquez au passage la déclaration du middleware guest dans les routes de Fortify (il faut aller voir ça dans le dossier vendor) :

Route::get('/register', [RegisteredUserController::class, 'create'])
    ->middleware(['guest:'.config('fortify.guard')])
    ->name('register');

En effet si on est authentifié c’est qu’on n’a pas besoin de s’enregistrer !

La vue register

On va donc chercher cette vue :

Elle a cet aspect :

Cette vue utilise le composant resources/views/layouts/guest.blade.php. Je n’ai pas encore parlé des composants de Blade dans ce cours, c’est une autre manière d’organiser le code des vues, la documentation est ici. Jetstream fait un usage intensif de ces composants. Je ne vais pas entrer dans le détail du code.

La validation

La validation pour l’enregistrement est présente dans l’action app/Actions/Fortify/CreateNewUser :

public function create(array $input)
{
    Validator::make($input, [
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
        'password' => $this->passwordRules(),
        'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['accepted', 'required'] : '',
    ])->validate();

    ...
}

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 :

Je rappelle qu’on peut ajouter la langue française avec ce complément.

La création de l’utilisateur

La création de l’utilisateur se fait aussi dans app/Actions/Fortify/CreateNewUser :

public function create(array $input)
{
    ...

    return User::create([
        'name' => $input['name'],
        'email' => $input['email'],
        'password' => Hash::make($input['password']),
    ]);
}

On utilise la méthode create d’Eloquent comme on l’a déjà vu au chapitre précédent. 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.

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

La connexion d’un utilisateur

Pour se connecter, un utilisateur doit cliquer sur le lien login de la page d’accueil :

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

Si on clique sur Login on appelle une méthode de Fortify :

Remarquez aussi la déclaration du middleware guest dans les routes de Fortify (il faut aller voir ça dans le dossier vendor) :

Route::post('/login', [AuthenticatedSessionController::class, 'store'])
    ->middleware(array_filter([
        'guest:'.config('fortify.guard'),
        $limiter ? 'throttle:'.$limiter : null,
    ]));

La vue login

On va donc chercher cette vue :

Elle a cet aspect :

Cette vue utilise aussi le composant resources/views/layouts/guest.blade.php.

La validation

La validation pour la connexion est présente dans la requête de formulaire fortify\src\Http\Requests\LoginRequest :

public function rules()
{
    return [
        Fortify::username() => 'required|string',
        'password' => 'required|string',
    ];
}

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.

La redirection

Lorsqu’on installe Fortify on a la création d’un fichier de configuration :

On y trouve un configuration de la redirection après la connexion :

'home' => RouteServiceProvider::HOME,

Dans le provider on a le chemin de redirection :

public const HOME = '/dashboard';

Par défaut on redirige sur le dashboard. Donc pour changer la redirection par défaut il suffit de créer cette propriété.

En fait ce que j’ai écrit ci-dessus est incomplet, il faut préciser quelque chose. On peut arriver sur le formulaire de connexion parce qu’on clique sur le lien correspondant, mais on peut aussi y arriver par l’action du middleware auth. En effet si on veut atteindre une page pour laquelle il faut être authentifié le middleware auth va nous bloquer et nous rediriger sur le formulaire de connexion. Dans ce cas ce qui serait bien serait, à l’issue de la connexion, d’aller directement sur la page qu’on désirait atteindre au départ.Sans entrer dans les détails la route désirée est mémorisée dans la session.

La déconnexion d’un utilisateur

L’utilisateur dispose d’un lien pour se déconnecter :

Si on clique sur Logout on appelle une méthode de Fortify :

Remarquez que la méthode est POST. Du coup la vue (navigation-menu) utilise un formulaire et une soumission en Javascript :

<!-- Authentication -->
<form method="POST" action="{{ route('logout') }}">
    @csrf

    <x-jet-dropdown-link href="{{ route('logout') }}"
                onclick="event.preventDefault();
                    this.closest('form').submit();">
        {{ __('Log Out') }}
    </x-jet-dropdown-link>
</form>

C’est la méthode destroy du contrôleur AuthenticatedSessionController de Fortify qui accomplit la déconnexion :

public function destroy(Request $request): LogoutResponse
{
    $this->guard->logout();
    $request->session()->invalidate();
    $request->session()->regenerateToken();
    return app(LogoutResponse::class);
}

Si on veut changer des choses

Tout ce qu’on a vu fonctionne très bien mais évidemment il arrive souvent qu’on veuille changer des choses, faisons un petit point…

Changer l’email de connexion

Par défaut on attend un email pour se connecter, mais comment faire si on préfre utiliser par exemple le nom ? Il suffit d’aller dans le fichier de configuration de Fortify (config/fortify.php) et de modifier cette ligne de code :

'username' => 'email',

Le règles du mot de passe

Par défaut le mot de passe doit avoir au minimum 8 caractères et c’est tout ce qu’on exige de lui. Si on a envie de rendre les mots de passe plus sûr on peut ajouter d’autres contraintes. Ouvrez ce fichier d’action :

Vous y trouvez les règles de validation du mot de passe :

protected function passwordRules()
{
    return ['required', 'string', new Password, 'confirmed'];
}

C’est sur l’objet Password qu’on peut intervenir :

(new Password)->length(10)

// Au moins une majuscule
(new Password)->requireUppercase()

// Au moins un chiffre
(new Password)->requireNumeric()

// Au moins un caractère spécial
(new Password)->requireSpecialCharacter()

La vérification de l’email

Par défaut Jetstream n’impose pas la vérification de l’email mais on peut très facilement activer cette fonctionnalité. Regardez dans le fichier de configuration de Fortify (config/fortify.php) :

'features' => [
    Features::registration(),
    Features::resetPasswords(),
    // Features::emailVerification(),
    Features::updateProfileInformation(),
    Features::updatePasswords(),
    Features::twoFactorAuthentication([
        'confirmPassword' => true,
    ]),
],

On trouve toutes les fonctionnalités de Jetstream. Pour le moment on n’a vu que la première, les utilisateurs peuvent s’enregistrer, se connecter et se déconnecter. Mais on voit qu’il y a d’autres possibilités, en particulier la vérification de l’email qui est par défaut commentée. Il suffit de la décommenter pour que ça fonctionne. Mais il faut aussi que le modèle User implémente l’interface MustVerifyEmail :

class User extends Authenticatable implements MustVerifyEmail

Maintenant lorsqu’un utilisateur s’enregistre il a ce message :

Et il reçoit cet email :

Lorqu’il utilise le lien d’activation il est automatiquement connecté.

Changer la langue

On a déjà vu qu’on peut ajouter le français à Laravel en utilisant Laravel-Lang. Je parlerai plus loin dans ce cours de la localisation et de la manière d’intervenir dans les vues.

En résumé

  • L’authentification est totalement et simplement prise en charge par Laravel.
  • Les migrations pour l’authentification sont déjà dans l’installation de base de Laravel.
  • L’ajout du package Jetstream permet de générer les routes et les vues pour l’authentification.
  • L’installation de Jetstream entraine l’installation de Fortify qui gère le backend de l’authentification.
Print Friendly, PDF & Email

4 commentaires

Laisser un commentaire