21 octobre 2021 173.531K

Formation Laravel : Middlewares

1. Middleware c’est quoi et ça marche comment ?

Maintenant je vais vous présenter les Middleware dans Laravel.

Un Middleware est une mini-application, une étape intermédiaire qui va envelopper les actions gérées par notre controller. Elle est une sorte de sous-couche se plaçant entre la requête (request) et la réponse (response) entre la vue et le controller.

Pour schématiser en reprenant notre graphique de l’architecture MVC du chapitre précédent cela donnerait quelque chose comme ça :

Illustration architecture MVC et Middleware - Walker Spider

Il sert à introduire une logique, une condition pour exécuter telle ou telle méthode présente dans le controller.

Laravel est installé avec quelques middlewares déjà présents, notamment :

• un système d’authentification afin de vous permettre de définir aisément si une méthode doit être exécuter si la personne est authentifiée ou non sur notre site web.
• un système de mode de maintenance afin de faire vos tambouilles tranquillement etc… 😉
• une vérification des tokens CSRF pour les envois de formulaire
etc…

Ces Middlewares se situent dans app/Http/Middleware

Arborescence Laravel - Dossier Middleware

Ouvrons l’un d’entre eux pour voir comment cela se passe. Prenons Authenticate.php

<?php

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;

class Authenticate extends Middleware
{
    /**
        * Get the path the user should be redirected to when they are not authenticated.
        *
        * @param  \Illuminate\Http\Request  $request
        * @return string
        */
    protected function redirectTo($request)
    {
        if (! $request->expectsJson()) {
            return route('login');
        }
    }
}

Heu… Ouais… Y a pas grand chose !

En effet, Laravel en montre le moins possible en surface afin d’épuré au maximum le code. Mais si vous faites un peu attention vous voyez que nous avons un extends de la Class Middleware qui est en réalité la Class Authenticate situé dans le namespace Illuminate\Auth\Middleware\Authenticate. Donc en vous y rendant (les dossiers et fichiers sont ordonnés de la même manière que les namespace) vous trouverez le code utilisé pour ce middleware Authenticate.

<?php

namespace Illuminate\Auth\Middleware;

use Closure;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Auth\Factory as Auth;

class Authenticate
{
    /**
        * The authentication factory instance.
        *
        * @var \Illuminate\Contracts\Auth\Factory
        */
    protected $auth;

    /**
        * Create a new middleware instance.
        *
        * @param  \Illuminate\Contracts\Auth\Factory  $auth
        * @return void
        */
    public function __construct(Auth $auth)
    {
        $this->auth = $auth;
    }

    /**
        * Handle an incoming request.
        *
        * @param  \Illuminate\Http\Request  $request
        * @param  \Closure  $next
        * @param  string[]  ...$guards
        * @return mixed
        *
        * @throws \Illuminate\Auth\AuthenticationException
        */
    public function handle($request, Closure $next, ...$guards)
    {
        $this->authenticate($request, $guards);

        return $next($request);
    }

    /**
        * Determine if the user is logged in to any of the given guards.
        *
        * @param  \Illuminate\Http\Request  $request
        * @param  array  $guards
        * @return void
        *
        * @throws \Illuminate\Auth\AuthenticationException
        */
    protected function authenticate($request, array $guards)
    {
        if (empty($guards)) {
            $guards = [null];
        }

        foreach ($guards as $guard) {
            if ($this->auth->guard($guard)->check()) {
                return $this->auth->shouldUse($guard);
            }
        }

        throw new AuthenticationException(
            'Unauthenticated.', $guards, $this->redirectTo($request)
        );
    }

    /**
        * Get the path the user should be redirected to when they are not authenticated.
        *
        * @param  \Illuminate\Http\Request  $request
        * @return string
        */
    protected function redirectTo($request)
    {
        //
    }
}

Ici nous avons notre méthode principale handle() qui prend en paramètres :
• la requête $request pour récupérer les données passées.
• une Closure $next qui nous permettra de faire continuer la requête si les conditions requises sont validées en faisant un return $next($request);
• et un array $guards qui définit les manière d’authentification (vous pouvez les retrouver dans config/auth.php, il y en a 2 par défaut ‘web’ et ‘api’).

Cette méthode fait appel à une autre méthode authenticate() qui permet de définir si l’utilisateur et bel et bien authentifié. Puis s’il n’est pas authentifié cette méthode renvoie une exception qui fait appel à la méthode redirectTo() pour rediriger l’utilisateur. Et S’il est bien authentifié on retourne :

return $next($request);

À noter que la méthode redirectTo() nous la retrouvons dans notre Authenticate.php située dans app/Http/Middleware. Cet exemple nous montre de nouveau comment Laravel nous épuré le code en surface en nous prenons le nécessaire en amont.

2. Mettre en place l’auth de Laravel

Laravel vous propose donc de mettre directement en place un système gérant l’authentification de vos utilisateurs. Comme nous venons de le voir le middleware est déjà présent mais il manque les views et les controllers ainsi que les routes. Pour les générer il vous suffit de lancer la commande :

php artisan make:auth

À la fin de l’installation vous pourrez voir que de nouveaux éléments sont présents dans votre projet. Les principaux sont :

• les fichiers views situés dans resources/views/auth

Arborescence Laravel - Dossier views auth

Qui nous permettront d’afficher les pages pour s’inscrire, se connecter, reset son mot de passe etc…

• les controllers également regroupés dans un dossier Auth dans les Controllers :

Arborescence Laravel - Dossier Controllers Auth

• 2 nouvelles lignes dans notre fichier web.php

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

La première est Auth:routes(), elle génère les routes de notre système d’authentification et la deuxième est une route : '/home' ; qui prend en action la méthode index() du controller HomeController.

Ce controller a également été ajouté voyons vers ce qu’il y a :

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    /**
        * Create a new controller instance.
        *
        * @return void
        */
    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
        * Show the application dashboard.
        *
        * @return \Illuminate\Http\Response
        */
    public function index()
    {
        return view('home');
    }
}

On peut voir que l’on définit très simplement le middleware dans le __construct() de notre Class HomeController et dans notre méthode index() on renvoie une vue nommée ‘home’.

Voyons dans la pratique comment ça marche.

Rendons-nous de nouveau sur notre homepage : 127.0.0.1:8000

Screen Laravel - Homepage - Authentification

On remarque que 2 liens ont été ajoutés. Un lien pour se connecter, l’autre pour s’inscrire.

Maintenant en essayant de nous rendre sur 127.0.0.1:8000/home on remarque que l’on est automatiquement redirigé vers la route ‘/login’.

Screen Laravel - Page Login

Je pense que vous commencez à comprendre tout seul n’est-ce-pas ? 🙂
Dans le __construct() de HomeController on a notre middleware qui l’enveloppe (cf schéma plus haut). Et s’il on n’est pas authentifié la méthode redirectTo() du middleware qui se trouve dans Authenticate.php que nous avons vu précédemment, rentre en action et nous retourne la route ‘login’. Nous pouvons voir dans notre barre de debug que cette route correspond à la méthode showLoginForm() de LoginController. En se rendant à cette Class on remarque que celle-ci utilise la Class AuthenticatesUsers.

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
        * Where to redirect users after login.
        *
        * @var string
        */
    protected $redirectTo = '/home';

    /**
        * Create a new controller instance.
        *
        * @return void
        */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }
}

Et en allant voir à son tour la Class AuthenticatesUsers nous retrouvons bien notre méthode showLoginForm() qui retourne la vue ‘auth.login’ présente dans notre dossier resources/auth

<?php

namespace Illuminate\Foundation\Auth;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;

trait AuthenticatesUsers
{
    use RedirectsUsers, ThrottlesLogins;

    /**
        * Show the application's login form.
        *
        * @return \Illuminate\Http\Response
        */
    public function showLoginForm()
    {
        return view('auth.login');
    }
    
    /*
    ...
    */
}

Ok je comprends la logique ! Mais comment marche ce $this->middleware() dans les __construct() des Controllers ?

Et bien il s’agit d’une des 2 manières pour appliquer un middleware :

1 – Je veux appliquer mon middleware seulement sur quelques routes et j’utilise donc la méthode middleware() que l’on vient de voir en mettant en paramètre le nom du middleware :

$this->middleware('auth');

2 – Je veux appliquer mon middleware sur l’ensemble de mon application. Dans ce cas je me rends dans mon fichier Kernel.php se trouvant dans app/Http/Kernel.php et j’ajoute le namespace de mon middleware dans le tableau adéquat :

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    /**
        * The application's global HTTP middleware stack.
        *
        * These middleware are run during every request to your application.
        *
        * @var array
        */
    protected $middleware = [
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\TrustProxies::class,
    ];

    /**
        * The application's route middleware groups.
        *
        * @var array
        */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

    /**
        * The application's route middleware.
        *
        * These middleware may be assigned to groups or used individually.
        *
        * @var array
        */
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    ];

    /**
        * The priority-sorted list of middleware.
        *
        * This forces non-global middleware to always be in the given order.
        *
        * @var array
        */
    protected $middlewarePriority = [
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\Authenticate::class,
        \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \Illuminate\Auth\Middleware\Authorize::class,
    ];
}

À noter que c’est ici aussi que vous définissez le nom de votre middleware (que vous mettez en paramètre si vous souhaitez utiliser le middleware sur une partie de votre application). C’est exactement le même principe que les alias pour les Services Providers.

Voilà nous avons vu l’ensemble de l’architecture MVC de Laravel et avons même mis en place le système d’authentification. Cependant pour pouvoir s’authentifier et avoir des utilisateurs qui s’inscrivent il faut avoir une base de données pour stocker leur login et autres infos non ? 🙂

C’est pourquoi je vous propose de passer à la Partie 2 de ce cours qui traitera sur l’ensemble de la gestion de la Base de Données avec Laravel.

Besoin d'une formation personalisée ?

Avis

4,9
Rated 4.9 out of 5
Excellent88%
Splendide !12%
Sympa0%
Sans plus0%
Pas terrible0%

Pas de titre

Rated 5 out of 5
15 avril 2024

cool

paul

Pas de titre

Rated 5 out of 5
2 avril 2024
Evelyn

Pas de titre

Rated 4 out of 5
2 avril 2024

Merci beaucoup pour ce cour.

adil

Pas de titre

Rated 5 out of 5
7 mars 2024

super

hajar

Pas de titre

Rated 5 out of 5
21 juin 2023

Merci énormément je suis sur exciter à cause de ce cours

Kassi Patrick