Laravel Middleware in Dettaglio: Autenticazione, Rate Limiting e Middleware Personalizzati

Guida ai middleware Laravel con esempi pratici su guard di autenticazione, rate limiting con throttle, creazione di middleware personalizzati, attributi PHP in Laravel 13 e pattern avanzati per applicazioni in produzione.

Architettura middleware di Laravel con pipeline delle richieste, autenticazione e rate limiting

Laravel middleware funge da strato di filtraggio tra le richieste HTTP in arrivo e la logica applicativa. Ogni richiesta passa attraverso una pipeline di classi middleware prima di raggiungere un controller, e ogni risposta attraversa la stessa pipeline al ritorno. La comprensione di questo meccanismo e essenziale per costruire applicazioni Laravel sicure e performanti.

Middleware in sintesi

I middleware intercettano le richieste HTTP prima che raggiungano le route. Laravel registra tutti i middleware in bootstrap/app.php utilizzando una API fluent. I middleware integrati gestiscono autenticazione, protezione CSRF, gestione delle sessioni e rate limiting.

Come funziona la pipeline middleware di Laravel

Il kernel HTTP di Laravel elabora ogni richiesta attraverso uno stack di middleware. Ogni middleware riceve la richiesta, esegue la propria logica e passa la richiesta al livello successivo tramite $next($request) oppure interrompe la pipeline restituendo direttamente una risposta.

Questa architettura segue il pattern Chain of Responsibility. I middleware possono agire prima che la richiesta raggiunga il controller (es. controlli di autenticazione), dopo la generazione della risposta (es. aggiunta di header), o in entrambe le fasi.

app/Http/Middleware/LogRequestTime.phpphp
namespace AppHttpMiddleware;

use Closure;
use IlluminateHttpRequest;
use IlluminateSupportFacadesLog;
use SymfonyComponentHttpFoundationResponse;

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
    }
}

Questo middleware avvolge la richiesta: registra il tempo di inizio prima dell'elaborazione e logga la durata dopo il ritorno della risposta. Questo pattern before/after e centrale nel funzionamento dei middleware.

Authentication Middleware: Protezione delle Route

Laravel include l'alias middleware auth, mappato su IlluminateAuthMiddlewareAuthenticate. Applicarlo a una route assicura che solo gli utenti autenticati possano accedervi. Gli utenti non autenticati ricevono una risposta 401 (API) o vengono reindirizzati alla pagina di login (web).

routes/web.phpphp
use AppHttpControllersDashboardController;
use AppHttpControllersProfileController;

// 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']);
});

Autenticazione Multi-Guard

Le applicazioni con piu tipologie di utenti (pannello admin, area clienti, API) beneficiano dell'autenticazione basata su guard. Il middleware auth accetta un parametro guard per specificare quale driver di autenticazione utilizzare.

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']);
});

Il parametro guard dopo i due punti indica a Laravel quale configurazione di autenticazione verificare. Questo mantiene la logica di autenticazione pulita e separata tra le diverse aree dell'applicazione.

Guest Middleware

Il middleware guest e l'inverso di auth: permette il passaggio solo agli utenti non autenticati. Applicandolo alle route di login e registrazione si impedisce agli utenti gia autenticati di accedere a quelle pagine.

Rate Limiting con Throttle Middleware

Il rate limiting middleware di Laravel protegge le route dagli abusi utilizzando il middleware integrato throttle. La forma piu semplice accetta due parametri: il numero massimo di richieste e la finestra temporale in minuti.

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 Limiter Nominati per Controllo Avanzato

Definire rate limiter nominati nel AppServiceProvider offre un controllo granulare sui limiti in base al contesto utente. Questo approccio e piu flessibile dei parametri throttle inline. La documentazione ufficiale sul rate limiting offre opzioni aggiuntive.

app/Providers/AppServiceProvider.phpphp
use IlluminateCacheRateLimitingLimit;
use IlluminateSupportFacadesRateLimiter;
use IlluminateHttpRequest;

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'applicazione dei limiter nominati alle route usa la sintassi throttle:nome:

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']);

Il rate limiter a livelli sopra dimostra un pattern di produzione: gli utenti enterprise ottengono limiti piu alti, gli utenti autenticati limiti moderati, e le richieste anonime vengono limitate in modo aggressivo. Il metodo by() determina la chiave del rate limit, usando l'ID utente per gli utenti autenticati e l'indirizzo IP come fallback.

Pronto a superare i tuoi colloqui su Laravel?

Pratica con i nostri simulatori interattivi, flashcards e test tecnici.

Costruire Middleware Personalizzati da Zero

La creazione di middleware personalizzati copre scenari che i middleware integrati non gestiscono. Il comando Artisan make:middleware genera una nuova classe con la struttura corretta.

bash
php artisan make:middleware EnsureUserHasRole

Middleware per Controllo Accessi Basato sui Ruoli

Un pattern comune per middleware personalizzati e l'autorizzazione basata sui ruoli a livello di route, accettando nomi di ruoli come parametri.

app/Http/Middleware/EnsureUserHasRole.phpphp
namespace AppHttpMiddleware;

use Closure;
use IlluminateHttpRequest;
use SymfonyComponentHttpFoundationResponse;

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);
    }
}

Il parametro variadic ...$roles permette di passare piu ruoli separati da virgola. Registrazione e utilizzo appaiono cosi:

bootstrap/app.phpphp
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'role' => AppHttpMiddlewareEnsureUserHasRole::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 per Trasformazione delle Richieste

I middleware possono modificare la richiesta prima che raggiunga il controller. Un middleware per API JSON che impone header content type e trim degli input stringa:

app/Http/Middleware/ApiRequestSanitizer.phpphp
namespace AppHttpMiddleware;

use Closure;
use IlluminateHttpRequest;
use SymfonyComponentHttpFoundationResponse;

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);
    }
}

Questo middleware gestisce due aspetti: valida il content type per le richieste POST e sanitizza tutti gli input stringa rimuovendo gli spazi.

Registrazione dei Middleware in bootstrap/app.php

Laravel centralizza tutta la registrazione dei middleware in bootstrap/app.php. Questo ha sostituito l'approccio precedente app/Http/Kernel.php che esisteva prima di Laravel 11. La stessa API fluent funziona in Laravel 12 e 13.

bootstrap/app.phpphp
use IlluminateFoundationApplication;
use IlluminateFoundationConfigurationMiddleware;

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

        // Add to the 'web' middleware group
        $middleware->web(append: [
            AppHttpMiddlewareTrackPageViews::class,
        ]);

        // Add to the 'api' middleware group
        $middleware->api(prepend: [
            AppHttpMiddlewareApiRequestSanitizer::class,
        ]);

        // Register aliases for route-level use
        $middleware->alias([
            'role'       => AppHttpMiddlewareEnsureUserHasRole::class,
            'subscribed' => AppHttpMiddlewareEnsureUserIsSubscribed::class,
        ]);

        // Control execution order
        $middleware->priority([
            IlluminateSessionMiddlewareStartSession::class,
            IlluminateAuthMiddlewareAuthenticate::class,
            AppHttpMiddlewareEnsureUserHasRole::class,
        ]);
    })
    ->create();

L'array priority e importante quando piu middleware sono assegnati alla stessa route. Laravel li ordina secondo questa lista, assicurando che la sessione sia avviata prima dell'autenticazione, e l'autenticazione sia completata prima dei controlli sui ruoli.

Ordine di Esecuzione dei Middleware

I middleware vengono eseguiti nell'ordine di registrazione. Per i middleware a livello di route, l'array priority sovrascrive l'ordine predefinito. L'autenticazione deve sempre precedere i middleware di autorizzazione per evitare di verificare i ruoli su richieste non autenticate.

Attributi PHP per Middleware in Laravel 13

Laravel 13 ha introdotto l'attributo PHP #[Middleware] per dichiarare middleware direttamente su classi e metodi dei controller. Questo approccio mantiene la configurazione middleware co-localizzata con il codice che protegge, rendendo le regole di autorizzazione piu leggibili e manutenibili.

app/Http/Controllers/CommentController.phpphp
namespace AppHttpControllers;

use AppModelsComment;
use AppModelsPost;
use IlluminateRoutingAttributesControllersAuthorize;
use IlluminateRoutingAttributesControllersMiddleware;

#[Middleware('auth')]
class CommentController
{
    #[Middleware('subscribed')]
    #[Authorize('create', [Comment::class, 'post'])]
    public function store(Post $post)
    {
        // Only authenticated, subscribed users who can create comments reach here
    }

    public function index(Post $post)
    {
        // Still requires auth (from class-level attribute)
        return $post->comments;
    }
}

L'attributo #[Middleware('auth')] a livello di classe si applica a tutti i metodi. Gli attributi a livello di metodo si sommano: store() richiede sia auth che subscribed. L'attributo #[Authorize] si integra con il sistema di policy di Laravel, verificando i permessi prima dell'esecuzione del metodo.

Questo approccio basato su attributi e opzionale. La registrazione middleware nei file di route e in bootstrap/app.php rimane pienamente supportata. I team che preferiscono definizioni di route esplicite possono continuare a usare l'API fluent; i team che desiderano controller auto-documentanti possono adottare gli attributi.

Terminable Middleware per Task Post-Response

I terminable middleware eseguono logica dopo che la risposta e stata inviata al client. Questo e utile per logging, analytics o task di pulizia che non devono bloccare l'utente.

app/Http/Middleware/CollectAnalytics.phpphp
namespace AppHttpMiddleware;

use Closure;
use IlluminateHttpRequest;
use IlluminateSupportFacadesDB;
use SymfonyComponentHttpFoundationResponse;

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(),
        ]);
    }
}

Il metodo terminate riceve sia la richiesta originale che la risposta finale. Il middleware deve essere registrato come singleton nel AppServiceProvider per assicurare che la stessa istanza gestisca sia handle() che terminate().

Pattern Middleware Pratici per la Produzione

Diversi pattern middleware appaiono costantemente nelle applicazioni Laravel in produzione.

Bypass della modalita manutenzione permette agli IP interni di accedere all'applicazione durante la manutenzione:

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);
    }
}

Security header aggiungono HSTS, content security policy e altri header a ogni risposta:

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;
    }
}

Questi pattern dimostrano le due posizioni primarie dei middleware: prima della richiesta (il bypass manutenzione verifica l'IP e potenzialmente blocca) e dopo la risposta (i security header modificano la risposta in uscita).

Pronto a superare i tuoi colloqui su Laravel?

Pratica con i nostri simulatori interattivi, flashcards e test tecnici.

Fonti

Pattern Middleware Laravel per la Preparazione ai Colloqui

  • I middleware Laravel operano come pipeline: ogni classe elabora la richiesta, agisce su di essa e la passa avanti o interrompe con una risposta
  • Il middleware auth protegge le route con autenticazione basata su guard, supportando piu tipi di utente tramite la sintassi auth:guard
  • Il rate limiting tramite middleware throttle e definizioni nominali RateLimiter::for() permette controllo accessi a livelli basato sul contesto utente
  • I middleware personalizzati gestiscono aspetti trasversali come verifica ruoli, sanitizzazione richieste e security header senza appesantire i controller
  • Tutta la registrazione middleware avviene in bootstrap/app.php usando una API fluent, con priority che controlla l'ordine di esecuzione
  • L'attributo #[Middleware] di Laravel 13 permette di dichiarare middleware direttamente sui controller, mantenendo le regole di autorizzazione co-localizzate con i gestori
  • I terminable middleware eseguono task post-response (analytics, logging) senza impattare la latenza percepita dall'utente
  • I parametri middleware tramite la sintassi :param mantengono le definizioni delle route espressive e le classi middleware riutilizzabili in contesti diversi

Inizia a praticare!

Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.

Sfida del giorno

Sapresti trovare il bug in Laravel?

Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Anthony Fillion-Maillet

Scritto da

Anthony Fillion-Maillet

Fondatore di SharpSkill

Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.

Aggiornato il 21 settembre 2026

Tag

#laravel
#middleware
#autenticazione
#rate-limiting
#php

Condividi

Articoli correlati