Laravel Middleware en profondeur : Authentification, Rate Limiting et Middleware personnalisé

Exploration complète des middleware Laravel avec des exemples pratiques : gardes d'authentification, limitation de débit avec throttle, création de middleware personnalisé et patterns avancés pour les applications en production.

Architecture des middleware Laravel montrant le pipeline de requêtes avec les couches d'authentification et de limitation de débit

Les middleware Laravel constituent une couche de filtrage entre les requêtes HTTP entrantes et la logique applicative. Chaque requête transite par un pipeline de classes middleware avant d'atteindre un contrôleur, et chaque réponse effectue le chemin inverse à travers le même pipeline. La maîtrise de ce mécanisme est indispensable pour construire des applications Laravel sécurisées et performantes en 2026.

Les middleware en résumé

Les middleware interceptent les requêtes HTTP avant qu'elles n'atteignent les routes. Laravel 12 enregistre tous les middleware dans bootstrap/app.php via une API fluide. Les middleware intégrés gèrent l'authentification, la protection CSRF, la gestion des sessions et la limitation de débit de manière native.

Fonctionnement du pipeline middleware dans Laravel

Le kernel HTTP de Laravel traite chaque requête à travers une pile de middleware. Chaque middleware reçoit la requête, exécute sa logique, puis soit transmet la requête à la couche suivante via $next($request), soit court-circuite le pipeline en retournant directement une réponse.

Cette architecture suit le design pattern Chain of Responsibility. Un middleware peut agir avant que la requête atteigne le contrôleur (par exemple, vérification d'authentification), après la génération de la réponse (par exemple, ajout d'en-têtes), ou les deux à la fois.

app/Http/Middleware/LogRequestTime.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;

class LogRequestTime
{
    public function handle(Request $request, Closure $next): Response
    {
        $start = microtime(true);          // Capture start time

        $response = $next($request);       // Pass to next middleware

        $duration = microtime(true) - $start;
        Log::info('Request completed', [
            'url'      => $request->url(),
            'method'   => $request->method(),
            'duration' => round($duration * 1000, 2) . 'ms',
        ]);

        return $response;                  // Return response up the stack
    }
}

Ce middleware encapsule la requête : il enregistre le temps de départ avant le traitement et journalise la durée après le retour de la réponse. Ce schéma avant/après est au coeur du fonctionnement des middleware.

Middleware d'authentification : protéger les routes

Laravel fournit l'alias middleware auth, associé à Illuminate\Auth\Middleware\Authenticate. Son application à une route garantit que seuls les utilisateurs authentifiés peuvent y accéder. Les utilisateurs non authentifiés reçoivent une réponse 401 (API) ou sont redirigés vers la page de connexion (web).

routes/web.phpphp
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\ProfileController;

// Single route protection
Route::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware('auth');

// Group protection for multiple routes
Route::middleware('auth')->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
    Route::put('/profile', [ProfileController::class, 'update']);
    Route::delete('/profile', [ProfileController::class, 'destroy']);
});

Authentification multi-guards

Les applications comportant plusieurs types d'utilisateurs (panneau d'administration, espace client, API) tirent parti de l'authentification par guard. Le middleware auth accepte un paramètre de guard pour spécifier quel pilote d'authentification utiliser.

routes/api.phpphp
// API routes use the 'sanctum' guard
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', fn (Request $request) => $request->user());
    Route::apiResource('/orders', OrderController::class);
});

// routes/web.php
// Admin routes use a custom 'admin' guard
Route::middleware('auth:admin')->prefix('admin')->group(function () {
    Route::get('/dashboard', [AdminController::class, 'index']);
    Route::get('/users', [AdminController::class, 'users']);
});

Le paramètre de guard après les deux-points indique à Laravel quelle configuration d'authentification vérifier. Cette approche permet de séparer proprement la logique d'authentification entre les différentes parties de l'application.

Middleware Guest

Le middleware guest est l'inverse de auth : il ne laisse passer que les utilisateurs non authentifiés. Son application aux routes de connexion et d'inscription empêche les utilisateurs déjà authentifiés d'accéder à ces pages.

Limitation de débit avec le middleware Throttle

La limitation de débit via les middleware Laravel protège les routes contre les abus grâce au middleware intégré throttle. Sa forme la plus simple accepte deux paramètres : le nombre maximum de requêtes et la fenêtre temporelle en minutes.

routes/api.phpphp
// Allow 60 requests per minute per user
Route::middleware('throttle:60,1')->group(function () {
    Route::get('/posts', [PostController::class, 'index']);
    Route::get('/posts/{post}', [PostController::class, 'show']);
});

// Stricter limit for write operations
Route::middleware(['auth:sanctum', 'throttle:10,1'])->group(function () {
    Route::post('/posts', [PostController::class, 'store']);
    Route::put('/posts/{post}', [PostController::class, 'update']);
});

Rate limiters nommés pour un contrôle avancé

La définition de rate limiters nommés dans AppServiceProvider offre un contrôle granulaire sur les limites en fonction du contexte utilisateur. Cette approche est plus flexible que les paramètres throttle en ligne.

app/Providers/AppServiceProvider.phpphp
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Http\Request;

public function boot(): void
{
    // API rate limiter with tiered access
    RateLimiter::for('api', function (Request $request) {
        $user = $request->user();

        if ($user?->hasSubscription('enterprise')) {
            return Limit::perMinute(500)->by($user->id);   // Enterprise: 500/min
        }

        if ($user) {
            return Limit::perMinute(100)->by($user->id);   // Authenticated: 100/min
        }

        return Limit::perMinute(20)->by($request->ip());   // Anonymous: 20/min
    });

    // Login limiter to prevent brute force
    RateLimiter::for('login', function (Request $request) {
        return Limit::perMinute(5)
            ->by($request->ip())                            // Key by IP address
            ->response(function () {                        // Custom exceeded response
                return response()->json([
                    'message' => 'Too many login attempts. Try again in a minute.',
                ], 429);
            });
    });
}

L'application des limiters nommés aux routes utilise la syntaxe throttle:name :

routes/api.phpphp
Route::middleware('throttle:api')->group(function () {
    Route::apiResource('/posts', PostController::class);
});

// routes/web.php
Route::middleware('throttle:login')
    ->post('/login', [AuthController::class, 'login']);

Le rate limiter par niveaux ci-dessus illustre un pattern de production : les utilisateurs entreprise obtiennent des limites plus élevées, les utilisateurs authentifiés des limites modérées, et les requêtes anonymes sont limitées de manière agressive. La méthode by() détermine la clé de limitation : l'identifiant utilisateur pour les utilisateurs authentifiés et l'adresse IP en solution de repli.

Prêt à réussir tes entretiens Laravel ?

Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.

Créer un middleware personnalisé de A à Z

La création de middleware personnalisé couvre les scénarios que les middleware intégrés ne gèrent pas. La commande Artisan make:middleware génère une nouvelle classe avec la structure appropriée.

bash
php artisan make:middleware EnsureUserHasRole

Middleware de contrôle d'accès par rôle

Un pattern courant de middleware personnalisé applique l'autorisation basée sur les rôles au niveau des routes, en acceptant les noms de rôles comme paramètres.

app/Http/Middleware/EnsureUserHasRole.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureUserHasRole
{
    public function handle(Request $request, Closure $next, string ...$roles): Response
    {
        $user = $request->user();

        if (! $user || ! $user->hasAnyRole($roles)) {
            abort(403, 'Insufficient permissions.');
        }

        return $next($request);
    }
}

Le paramètre variadique ...$roles permet de passer plusieurs rôles séparés par des virgules. L'enregistrement et l'utilisation se présentent ainsi :

bootstrap/app.phpphp
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'role' => \App\Http\Middleware\EnsureUserHasRole::class,
    ]);
})

// routes/web.php
Route::middleware('role:admin')->group(function () {
    Route::get('/admin', [AdminController::class, 'index']);
});

// Multiple roles: admin OR editor can access
Route::middleware('role:admin,editor')->group(function () {
    Route::resource('/articles', ArticleController::class);
});

Middleware de transformation de requête

Un middleware peut modifier la requête avant qu'elle n'atteigne le contrôleur. Voici un middleware pour API JSON qui impose les en-têtes de type de contenu et nettoie les entrées de type chaîne :

app/Http/Middleware/ApiRequestSanitizer.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class ApiRequestSanitizer
{
    public function handle(Request $request, Closure $next): Response
    {
        // Reject non-JSON requests on API routes
        if (! $request->expectsJson() && $request->isMethod('POST')) {
            return response()->json(
                ['error' => 'Content-Type must be application/json'],
                415
            );
        }

        // Trim all string inputs
        $input = $request->all();
        array_walk_recursive($input, function (&$value) {
            if (is_string($value)) {
                $value = trim($value);
            }
        });
        $request->merge($input);

        return $next($request);
    }
}

Ce middleware gère deux préoccupations : il valide le type de contenu pour les requêtes POST et assainit toutes les entrées textuelles en supprimant les espaces superflus.

Enregistrement des middleware dans Laravel 12

Laravel 12 centralise l'enregistrement de tous les middleware dans bootstrap/app.php. Cette approche remplace l'ancien fichier app/Http/Kernel.php qui existait avant Laravel 11.

bootstrap/app.phpphp
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware) {
        // Global middleware (runs on every request)
        $middleware->append(
            \App\Http\Middleware\LogRequestTime::class
        );

        // Add to the 'web' middleware group
        $middleware->web(append: [
            \App\Http\Middleware\TrackPageViews::class,
        ]);

        // Add to the 'api' middleware group
        $middleware->api(prepend: [
            \App\Http\Middleware\ApiRequestSanitizer::class,
        ]);

        // Register aliases for route-level use
        $middleware->alias([
            'role'       => \App\Http\Middleware\EnsureUserHasRole::class,
            'subscribed' => \App\Http\Middleware\EnsureUserIsSubscribed::class,
        ]);

        // Control execution order
        $middleware->priority([
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\Auth\Middleware\Authenticate::class,
            \App\Http\Middleware\EnsureUserHasRole::class,
        ]);
    })
    ->create();

Le tableau priority est important lorsque plusieurs middleware sont assignés à la même route. Laravel les trie selon cette liste, garantissant que la session est démarrée avant l'exécution de l'authentification, et que l'authentification est terminée avant les vérifications de rôle.

Ordre d'exécution des middleware

Les middleware s'exécutent dans l'ordre d'enregistrement. Pour les middleware de route, le tableau priority remplace l'ordre par défaut. Il faut toujours placer l'authentification avant l'autorisation pour éviter de vérifier les rôles sur des requêtes non authentifiées.

Middleware terminable pour les tâches post-réponse

Les middleware terminables exécutent une logique après l'envoi de la réponse au client. Cette fonctionnalité est utile pour la journalisation, l'analytique ou les tâches de nettoyage qui ne doivent pas bloquer l'utilisateur.

app/Http/Middleware/CollectAnalytics.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\Response;

class CollectAnalytics
{
    public function handle(Request $request, Closure $next): Response
    {
        return $next($request);  // Pass through without delay
    }

    public function terminate(Request $request, Response $response): void
    {
        // Runs after response is sent to client
        DB::table('analytics')->insert([
            'path'        => $request->path(),
            'method'      => $request->method(),
            'status_code' => $response->getStatusCode(),
            'user_id'     => $request->user()?->id,
            'ip'          => $request->ip(),
            'created_at'  => now(),
        ]);
    }
}

La méthode terminate reçoit à la fois la requête d'origine et la réponse finale. Il est recommandé d'enregistrer ce middleware comme singleton dans AppServiceProvider afin de garantir que la même instance gère à la fois handle() et terminate().

Patterns middleware avancés pour la production

Plusieurs patterns middleware reviennent régulièrement dans les applications Laravel en production.

Contournement du mode maintenance : permettre aux adresses IP internes d'accéder à l'application pendant la maintenance :

app/Http/Middleware/MaintenanceBypass.phpphp
class MaintenanceBypass
{
    private array $allowedIps = ['192.168.1.0/24', '10.0.0.1'];

    public function handle(Request $request, Closure $next): Response
    {
        if (app()->isDownForMaintenance()) {
            foreach ($this->allowedIps as $ip) {
                if ($request->ip() === $ip) {
                    return $next($request);
                }
            }
        }

        return $next($request);
    }
}

En-têtes de sécurité : ajouter HSTS, les politiques de sécurité du contenu et d'autres en-têtes à chaque réponse :

app/Http/Middleware/SecurityHeaders.phpphp
class SecurityHeaders
{
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        $response->headers->set('X-Content-Type-Options', 'nosniff');
        $response->headers->set('X-Frame-Options', 'SAMEORIGIN');
        $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
        $response->headers->set(
            'Strict-Transport-Security',
            'max-age=31536000; includeSubDomains'
        );

        return $response;
    }
}

Ces patterns illustrent les deux positions principales des middleware : avant la requête (le contournement de maintenance vérifie l'IP et bloque potentiellement) et après la réponse (les en-têtes de sécurité modifient la réponse sortante).

Prêt à réussir tes entretiens Laravel ?

Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.

Conclusion

  • Les middleware Laravel fonctionnent comme un pipeline : chaque classe traite la requête, agit dessus, puis la transmet ou court-circuite avec une réponse
  • Le middleware auth protège les routes avec une authentification par guard, supportant plusieurs types d'utilisateurs via la syntaxe auth:guard
  • La limitation de débit via le middleware throttle et les définitions nommées RateLimiter::for() permettent un contrôle d'accès par niveaux selon le contexte utilisateur
  • Les middleware personnalisés gèrent les préoccupations transversales comme les vérifications de rôle, l'assainissement des requêtes et les en-têtes de sécurité sans encombrer les contrôleurs
  • L'enregistrement de tous les middleware dans Laravel 12 se fait dans bootstrap/app.php via une API fluide, avec priority pour contrôler l'ordre d'exécution
  • Les middleware terminables exécutent des tâches post-réponse (analytique, journalisation) sans impacter la latence perçue par l'utilisateur
  • Les paramètres middleware via la syntaxe :param maintiennent des définitions de route expressives et des classes middleware réutilisables dans différents contextes

Passe à la pratique !

Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.

Tags

#laravel
#middleware
#authentication
#rate-limiting
#php

Partager

Articles similaires