Protéger nos pages avec un middleware

Dans ce tutoriel nous allons enfin extraire la vérification de l'authentification dans un système plus approprié : les middlewares.

Qu'est-ce qu'un middleware ?

Un middleware permet de court-circuiter une requête de l'utilisateur. Nous pouvons, avant l'exécution de contrôleur (l'affichage de la vue, la création d'un nouveau message, la modification du mot de passe…), effectuer des tests et rediriger si nécessaire la personne. C'est exactement ce que nous voulons faire dans nos quelques lignes de codes copiées dans CompteController@accueil, CompteController@modificationMotDePasse et MessagesController@nouveau.

Comment créer un middleware ?

Nous pouvons créer un middleware avec la commande Artisan :

php artisan make:middleware NomDuMiddleware

Dans notre cas nous pouvons simplement l'appeler Auth : php artisan make:middleware Auth.

Le fichier app/Http/Middleware/Auth.php

Dans le nouveau fichier créé par Laravel, il y a une simple classe Auth avec une seule fonction handle($request, Closure $next). La fonction handle() prend en paramètre la requête de l'utilisateur (identique à la fonction request()) et une fonction $next qui contient la suite de l'application.

Nous voulons pouvoir utiliser notre middleware sur plusieurs routes / contrôleurs différents, nous ne devons donc pas savoir ce qu'il y a après. La variable $next peut donc contenir soit la modification du mot de passe, soit l'affichage d'une vue mon-compte ou encore l'ajout d'un nouveau message. Pour le moment notre middleware return $next($request);, cela signifie à Laravel : « Exécute le reste de l'application et ne fait rien. ».

Nous pouvons ajouter avant cette ligne un message avec un die() pour bien voir quand ce middleware est appelé :

<?php

namespace App\Http\Middleware;

use Closure;

class Auth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        dump('Nous sommes dans le Auth middleware');
        die();

        return $next($request);
    }
}

Activation du middleware

Le middleware peut être activé sur n'importe quelle route. Dans le fichier routes/web.php, nous pouvons utiliser la fonction ->middleware() pour demander à Laravel d'activer le middleware :

Route::get('/', 'UtilisateursController@liste')->middleware('App\Http\Middleware\Auth');

Si vous actualisez la page d'accueil de l'application, vous devriez voir le message « Nous sommes dans le Auth middleware ».

Maintenant que nous avons vu que l'activation du middleware fonctionnait, nous pouvons remplacer le message par le « vrai » code :

<?php

namespace App\Http\Middleware;

use Closure;

class Auth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (auth()->guest()) {
            flash("Vous devez être connecté pour voir cette page.")->error();

            return redirect('/connexion');
        }

        return $next($request);
    }
}

Si vous réactualisez la page d'accueil, vous devriez être redirigé vers la page de connexion avec un message d'erreur.

Maintenant nous pouvons activer le middleware uniquement sur les routes qui nous intéressent avant de supprimer dans CompteController@accueil, CompteController@modificationMotDePasse et MessagesController@nouveau le code de vérification de l'authentification :

Route::get('/inscription', 'InscriptionController@formulaire');
Route::post('/inscription', 'InscriptionController@traitement');

Route::get('/connexion', 'ConnexionController@formulaire');
Route::post('/connexion', 'ConnexionController@traitement');

Route::get('/', 'UtilisateursController@liste');

Route::get('/mon-compte', 'CompteController@accueil')->middleware('App\Http\Middleware\Auth');
Route::get('/deconnexion', 'CompteController@deconnexion')->middleware('App\Http\Middleware\Auth');
Route::post('/modification-mot-de-passe', 'CompteController@modificationMotDePasse')->middleware('App\Http\Middleware\Auth');

Route::post('/messages', 'MessagesController@nouveau')->middleware('App\Http\Middleware\Auth');

Route::get('/{email}', 'UtilisateursController@voir');

Groupe de routes

Il est un peu lourd de devoir spécifier pour chaque route protégée le middleware à utiliser. Laravel vient avec un système de groupe de routes qui peut nous être utile.

Route::get('/inscription', 'InscriptionController@formulaire');
Route::post('/inscription', 'InscriptionController@traitement');

Route::get('/connexion', 'ConnexionController@formulaire');
Route::post('/connexion', 'ConnexionController@traitement');

Route::get('/', 'UtilisateursController@liste');

Route::group([
    'middleware' => 'App\Http\Middleware\Auth',
], function () {
    Route::get('/mon-compte', 'CompteController@accueil');
    Route::get('/deconnexion', 'CompteController@deconnexion');
    Route::post('/modification-mot-de-passe', 'CompteController@modificationMotDePasse');

    Route::post('/messages', 'MessagesController@nouveau');
});

Route::get('/{email}', 'UtilisateursController@voir');

Avec la fonction Route::group() nous créons un nouveau groupe. Le premier paramètre est un tableau d'options communes à tout le groupe, pour le moment nous n'indiquons que l'option middleware avec notre nouveau middleware. Le deuxième paramètre est une fonction anonyme qui contient toutes les routes que nous voulons protéger.

Déplacer une route dans la fonction anonyme la protégera via la connexion, la sortir de la fonction anonyme la rendra publique.

Comme vous pouvez le voir, le système des middlewares est très performant et très pratique à utiliser (activable ou désactivable à la demande), et c'est également un système très flexible qui permet de faire beaucoup plus de choses que de simplement rediriger la personne avec une condition.