Il middleware è una importante peculiarità di laravel, che permette di filtrare le request HTTP dirette verso la nostra applicazione.
Per esempio, si potrebbe utilizzare un middleware per consentire l’accesso ad una pagina solo agli utenti che possiedono determinati ruoli; oppure, come avviene in realtà in Laravel, utilizzare un middleware per gestire l’autenticazione degli utenti; o ancora un middleware potrebbe gestire il logging e registrare in un file di log le richieste che arrivano alla nostra applicazione.
Il comportamento di un middleware è il seguente:
- il middleware intercetta una Request
- Verifica delle condizioni
- Se le condizioni non sono soddisfatte, allora effettua un redirect verso una route predeterminata
- Se le condizioni richieste sono verificate, la richiesta viene processata normalmente.
In pratica, un middleware può essere visto come un layer che si interpone tra la richiesta e la risposta. Ad una Request possono essere associati più middleware.
Le classi che gestiscono i middleware si trovano all’interno della cartella app\Http\Middleware.
Per creare un nuovo Middleware basta utilizzare dalla riga di comando, dopo essersi posizionati all’interno della cartella che contiene l’applicazione, il comando php artisan make:middleware nome-middleware
cd laraapp
php artisan make:middleware ControllaMaggiorenne
Dopo aver digitato e inviato il comando, automaticamente verrà creato all’interno della cartella app\Http\Middleware il file ControllaMaggiorenne contenente la struttura della classe ControllaMaggiorenne.
<?php
namespace App\Http\Middleware;
use Closure;
class ControllaMaggiorenne
{
/**
* Gestisce le request in ingresso.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->age < 18) {
return redirect(‘minorenne’);
}
return $next($request);
}
}
Dando uno sguardo al codice si nota che tutto avviene all’interno del metodo pubblico handle, che prende come parametri la $request (contenente l’oggetto Request) e la callback $next che ha il compito di processare la request se le condizioni sono soddisfatte.
Registrare i Middleware
Se si vuole che un middleware venga applicato ad ogni richiesta, è necessario aggiungere la sua classe all’elenco assegnandola alla proprietà $middleware del file app/Http/Kernel.php.
protected $middleware = [
\Illuminate\Foundation\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,
\App\Http\Middleware\ControllaMaggiorenne::class,
]
Se invece si vuole assegnare un middleware a specifiche routes, allora è necessario assegnare una chiave al middleware ed elencarlo nella proprietà $routeMiddleware nel file app\Http\Kernel.php
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,
'controllamaggiorenne' => \App\Http\Middleware\ControllaMaggiorenne::class,
]
Una volta che il middleware è stato aggiunto all’elenco della variabile $routeMiddleware, per assegnarlo ad una route, all’interno del file routes/web.php, basta digitare una porzione di codice simile alla seguente:
Route::get(‘/contenutiparticolari/{age}’,function($age){
return “se sei arrivato qui è perché sei maggiorenne”;
})->middleware(‘controllamaggiorenne’);
E’ anche possibile assegnare ad una route più middleware:
Route::get(‘/profilo’,function() {
//
})->middleware(‘primo’,’secondo’);
Come si evince dal codice riportato sopra, per applicare più middleware è sufficiente elencarli separati da virgola.
Se più middleware devono essere applicati contemporaneamente a più routes, può tornare utile raggrupparli e creare un gruppo.
Laravel rende possibile creare un middleware group e per farlo è sufficiente utilizzare la proprietà $middlewareGroups all’interno del file app\Http\Kernel.php.
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'auth:api',
],
];
Come si può notare dal codice sopra, esistono già due middleware groups predefiniti (web e api), l’utente, se ha necessità, ne può aggiungere altri.
Per assegnare un middleware group ad una route è sufficiente scrivere un codice simile al seguente:
Route::get('/prova', function () {
//
})->middleware('web');
Route::group(['middleware' => ['web']], function () {
// Elencare qui tutte le routes che condividono il middleware group web
});
Come mostra il codice sopra, la sintassi per assegnare un middleware group è perfettamente uguale a quella utilizzata per assegnare un singolo middleware.
Un’altra caratteristica importante è quella che permette di passare parametri ad un middleware (esempio documentazione ufficiale):
<?php
namespace App\Http\Middleware;
use Closure;
class CheckRole
{
/**
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $role
* @return mixed
*/
public function handle($request, Closure $next, $role)
{
if (! $request->user()->hasRole($role)) {
// Redirect...
}
return $next($request);
}
}
Il codice seguente mostra come passare il parametro $role al middleware (documentazione ufficiale):
Route::put('post/{id}', function ($id) {
//
})->middleware('role:editor');
Si può notare che il valore del parametro è passato separandolo dal nome del middleware utilizzando il carattere : (due punti)