Prologo
Primi Passi
Architettura
Le Basi
- Routing
- Middleware
- Protezione da CSRF
- Controller
- Richieste
- Risposte
- Views
- Blade
- Vite
- URL
- Sessioni
- Validazione
- Errori
- Logging
Approfondimenti
- Artisan
- Broadcasting
- Cache
- Collezioni
- Concorrenza
- Contesto
- Contratti
- Eventi
- File System
- Helpers
- Client HTTP
- Localizzazione
- Notifiche
- Sviluppo di Package
- Processi
- Code
- Rate-limiting
- Stringhe
- Scheduling di Task
Sicurezza
Database
Eloquent ORM
Testing
Package
Middleware
- Introduzione
- Definizione dei Middleware
- Registrare Middleware
- Parametri del Middleware
- Middleware Terminabili
Introduzione
I Middleware offrono un meccanismo comodo per analizzare e filtrare le richieste HTTP che entrano nella tua applicazione. Ad esempio, Laravel include un middleware che verifica se l’utente della tua applicazione è autenticato. Se l’utente non è autenticato, il middleware reindirizzerà l’utente alla schermata di accesso della tua applicazione. Tuttavia, se l’utente è autenticato, il middleware permette alla richiesta di procedere ulteriormente nell’applicazione.
È possibile scrivere middleware aggiuntivi per eseguire diverse attività oltre all’autenticazione. Per esempio, un middleware per il logging potrebbe registrare tutte le richieste in arrivo nella tua applicazione. Laravel include diversi middleware, tra cui quelli per l’autenticazione e la protezione da CSRF. Tutti i middleware definiti dall’utente si trovano tipicamente nella directory app/Http/Middleware
della tua applicazione.
Definizione dei Middleware
Per creare un nuovo middleware, utilizza il comando Artisan make:middleware
:
php artisan make:middleware EnsureTokenIsValid
Questo comando inserirà una nuova classe EnsureTokenIsValid
nella directory app/Http/Middleware
. In questo middleware, consentiremo l’accesso alla route solo se il parametro token
fornito corrisponde a un valore specificato. Altrimenti, reindirizzeremo gli utenti all’URI /home
:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureTokenIsValid
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->input('token') !== 'my-secret-token') {
return redirect('/home');
}
return $next($request);
}
}
Come puoi vedere, se il token
fornito non corrisponde al nostro token segreto, il middleware effettuerà un reindirizzamento; altrimenti, la richiesta verrà inoltrata all’applicazione. Per inoltrare la richiesta più in profondità nell’applicazione (permettere al middleware di "passare"), viene chiamata la callback $next
con la $request
.
È meglio immaginare i middleware come una serie di "livelli" attraverso i quali le richieste HTTP devono passare prima di raggiungere la tua applicazione. Ogni livello può esaminare la richiesta e persino rifiutarla completamente.
Tutti i middleware sono risolti tramite il container dei servizi, quindi puoi specificare i tipi di qualsiasi dipendenza di cui hai bisogno nel costruttore di un middleware.
Middleware e Risposte
Naturalmente, un middleware può eseguire delle operazioni prima o dopo aver inoltrato la richiesta più in profondità nell’applicazione. Ad esempio, il middleware seguente eseguirà un’operazione prima che la richiesta venga gestita dall’applicazione:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class BeforeMiddleware
{
public function handle(Request $request, Closure $next): Response
{
// Perform action
return $next($request);
}
}
Tuttavia, questo altro middleware di seguito eseguirà la sua operazione dopo che la richiesta è stata gestita dall’applicazione:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class AfterMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
// Perform action
return $response;
}
}
Registrare Middleware
Middleware Globale
Se vuoi che un middleware venga eseguito durante ogni richiesta HTTP alla tua applicazione, puoi aggiungerlo allo stack dei middleware globali nel file bootstrap/app.php
della tua applicazione:
use App\Http\Middleware\EnsureTokenIsValid;
->withMiddleware(function (Middleware $middleware) {
$middleware->append(EnsureTokenIsValid::class);
})
L’oggetto $middleware
fornito alla closure withMiddleware
è un’istanza di Illuminate\Foundation\Configuration\Middleware
ed è responsabile della gestione dei middleware assegnati alle route della tua applicazione. Il metodo append
aggiunge il middleware alla fine della lista dei middleware globali. Se vuoi aggiungere un middleware all’inizio della lista, dovresti usare il metodo prepend
.
Gestione manuale del middleware globale predefinito di Laravel
Se desideri gestire manualmente la pila di middleware globale di Laravel, puoi fornire la pila predefinita dei middleware globali di Laravel al metodo use
. Successivamente, puoi modificare la pila di middleware predefinita secondo necessità:
->withMiddleware(function (Middleware $middleware) {
$middleware->use([
\Illuminate\Foundation\Http\Middleware\InvokeDeferredCallbacks::class,
// \Illuminate\Http\Middleware\TrustHosts::class,
\Illuminate\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Http\Middleware\ValidatePostSize::class,
\Illuminate\Foundation\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
]);
})
Assegnare Middleware alle Rotte
Se desideri assegnare middleware a rotte specifiche, puoi usare il metodo middleware
durante la definizione della rotta:
use App\Http\Middleware\EnsureTokenIsValid;
Route::get('/profile', function () {
// ...
})->middleware(EnsureTokenIsValid::class);
Puoi assegnare più middleware alla rotta passando un array di nomi di middleware al metodo middleware
:
Route::get('/', function () {
// ...
})->middleware([First::class, Second::class]);
Escludere un Middleware
Quando assegni un middleware a un gruppo di rotte, potresti aver bisogno di evitare che il middleware venga applicato a una singola rotta all’interno del gruppo. Puoi fare questo usando il metodo withoutMiddleware
:
use App\Http\Middleware\EnsureTokenIsValid;
Route::middleware([EnsureTokenIsValid::class])->group(function () {
Route::get('/', function () {
// ...
});
Route::get('/profile', function () {
// ...
})->withoutMiddleware([EnsureTokenIsValid::class]);
});
Puoi anche escludere un determinato set di middleware da un intero gruppo di definizioni di rotte:
use App\Http\Middleware\EnsureTokenIsValid;
Route::withoutMiddleware([EnsureTokenIsValid::class])->group(function () {
Route::get('/profile', function () {
// ...
});
});
Il metodo withoutMiddleware
può rimuovere solo middleware di rotta e non si applica ai middleware globali.
Gruppi Middleware
A volte potresti voler raggruppare diversi middleware sotto una singola chiave per assegnarli più facilmente alle rotte. Puoi fare questo utilizzando il metodo appendToGroup
nel file bootstrap/app.php
della tua applicazione:
use App\Http\Middleware\First;
use App\Http\Middleware\Second;
->withMiddleware(function (Middleware $middleware) {
$middleware->appendToGroup('group-name', [
First::class,
Second::class,
]);
$middleware->prependToGroup('group-name', [
First::class,
Second::class,
]);
})
I gruppi middleware possono essere assegnati alle rotte e alle azioni dei controller usando la stessa sintassi dei singoli middleware:
Route::get('/', function () {
// ...
})->middleware('group-name');
Route::middleware(['group-name'])->group(function () {
// ...
});
I Gruppi Middleware Predefiniti di Laravel
Laravel include i gruppi middleware predefiniti web
e api
che contengono middleware comuni che potresti voler applicare alle tue route web e API. Ricorda, Laravel applica automaticamente questi gruppi middleware ai corrispondenti file routes/web.php
e routes/api.php
:
Il Gruppo Middleware web |
---|
Illuminate\Cookie\Middleware\EncryptCookies |
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse |
Illuminate\Session\Middleware\StartSession |
Illuminate\View\Middleware\ShareErrorsFromSession |
Illuminate\Foundation\Http\Middleware\ValidateCsrfToken |
Illuminate\Routing\Middleware\SubstituteBindings |
Il Gruppo Middleware api |
---|
Illuminate\Routing\Middleware\SubstituteBindings |
Se desideri aggiungere o anteporre middleware a questi gruppi, puoi utilizzare i metodi web
e api
all’interno del file bootstrap/app.php
della tua applicazione. I metodi web
e api
sono alternative comode al metodo appendToGroup
:
use App\Http\Middleware\EnsureTokenIsValid;
use App\Http\Middleware\EnsureUserIsSubscribed;
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
EnsureUserIsSubscribed::class,
]);
$middleware->api(prepend: [
EnsureTokenIsValid::class,
]);
})
Puoi persino sostituire una delle voci predefinite del gruppo middleware di Laravel con un middleware personalizzato:
use App\Http\Middleware\StartCustomSession;
use Illuminate\Session\Middleware\StartSession;
$middleware->web(replace: [
StartSession::class => StartCustomSession::class,
]);
Oppure, puoi rimuovere completamente un middleware:
$middleware->web(remove: [
StartSession::class,
]);
Gestire Manualmente i Gruppi Middleware Predefiniti di Laravel
Se desideri gestire manualmente tutti i middleware all’interno dei gruppi middleware predefiniti web
e api
di Laravel, puoi ridefinire completamente i gruppi. L’esempio seguente definirà i gruppi middleware web
e api
con i loro middleware predefiniti, consentendoti di personalizzarli secondo necessità:
->withMiddleware(function (Middleware $middleware) {
$middleware->group('web', [
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
]);
$middleware->group('api', [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
// 'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
]);
})
> Di default, i gruppi middleware `web` e `api` vengono applicati automaticamente ai file corrispondenti `routes/web.php` e `routes/api.php` della tua applicazione dal file `bootstrap/app.php`.
<a name="alias-dei-middleware"></a>
### Alias dei Middleware
Puoi assegnare alias ai middleware nel file `bootstrap/app.php` della tua applicazione. Gli alias dei middleware ti permettono di definire un alias breve per una determinata classe di middleware, il che può essere particolarmente utile per middleware con nomi di classi lunghi:
```php
use App\Http\Middleware\EnsureUserIsSubscribed;
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'subscribed' => EnsureUserIsSubscribed::class
]);
})
Una volta che l’alias del middleware è stato definito nel file bootstrap/app.php
della tua applicazione, puoi utilizzare l’alias durante l’assegnazione del middleware alle route:
Route::get('/profile', function () {
// ...
})->middleware('subscribed');
Per comodità, alcuni middleware integrati di Laravel hanno già alias predefiniti. Ad esempio, il middleware auth
è un alias per il middleware Illuminate\Auth\Middleware\Authenticate
. Di seguito è riportato un elenco degli alias dei middleware predefiniti:
Alias | Middleware |
---|---|
auth |
Illuminate\Auth\Middleware\Authenticate |
auth.basic |
Illuminate\Auth\Middleware\AuthenticateWithBasicAuth |
auth.session |
Illuminate\Session\Middleware\AuthenticateSession |
cache.headers |
Illuminate\Http\Middleware\SetCacheHeaders |
can |
Illuminate\Auth\Middleware\Authorize |
guest |
Illuminate\Auth\Middleware\RedirectIfAuthenticated |
password.confirm |
Illuminate\Auth\Middleware\RequirePassword |
precognitive |
Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests |
signed |
Illuminate\Routing\Middleware\ValidateSignature |
subscribed |
\Spark\Http\Middleware\VerifyBillableIsSubscribed |
throttle |
Illuminate\Routing\Middleware\ThrottleRequests or Illuminate\Routing\Middleware\ThrottleRequestsWithRedis |
verified |
Illuminate\Auth\Middleware\EnsureEmailIsVerified |
Ordinamento dei Middleware
Raramente, potresti avere bisogno che il tuo middleware venga eseguito in un ordine specifico senza poter controllare l’ordine in cui sono assegnati alla route. In queste situazioni, puoi specificare la priorità del middleware utilizzando il metodo priority
nel file bootstrap/app.php
della tua applicazione:
->withMiddleware(function (Middleware $middleware) {
$middleware->priority([
\Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
\Illuminate\Auth\Middleware\Authorize::class,
]);
})
Parametri del Middleware
Il middleware può anche ricevere parametri aggiuntivi. Ad esempio, se la tua applicazione deve verificare che l’utente autenticato abbia un determinato "role" prima di eseguire una specifica azione, potresti creare un middleware EnsureUserHasRole
che riceve il nome di un role come argomento aggiuntivo.
I parametri aggiuntivi del middleware verranno passati al middleware dopo l’argomento $next
:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureUserHasRole
{
/**
* Gestisci una richiesta in arrivo.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, string $role): Response
{
if (! $request->user()->hasRole($role)) {
// Reindirizza...
}
return $next($request);
}
}
I parametri del middleware possono essere specificati quando si definisce la rotta separando il nome del middleware e i parametri con un :
:
use App\Http\Middleware\EnsureUserHasRole;
Route::put('/post/{id}', function (string $id) {
// ...
})->middleware(EnsureUserHasRole::class.':editor');
Parametri multipli possono essere delimitati da virgole:
Route::put('/post/{id}', function (string $id) {
// ...
})->middleware(EnsureUserHasRole::class.':editor,publisher');
Middleware Terminabili
A volte un middleware potrebbe aver bisogno di eseguire alcune operazioni dopo che la risposta HTTP è stata inviata al browser. Se definisci un metodo terminate
nel tuo middleware e il tuo server web utilizza FastCGI, il metodo terminate
verrà chiamato automaticamente dopo che la risposta è stata inviata al browser:
<?php
namespace Illuminate\Session\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class TerminatingMiddleware
{
/**
* Gestisce una richiesta in arrivo.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
/**
* Gestisce le operazioni dopo che la risposta è stata inviata al browser.
*/
public function terminate(Request $request, Response $response): void
{
// ...
}
}
Il metodo terminate
dovrebbe ricevere sia la richiesta che la risposta. Una volta definito un middleware terminabile, dovresti aggiungerlo alla lista dei middleware delle rotte o globale nel file bootstrap/app.php
della tua applicazione.
Quando viene chiamato il metodo terminate
sul tuo middleware, Laravel risolverà una nuova istanza del middleware dal service container. Se desideri utilizzare la stessa istanza del middleware quando vengono chiamati i metodi handle
e terminate
, registra il middleware nel contenitore utilizzando il metodo singleton
del contenitore. Tipicamente, questo dovrebbe essere fatto nel metodo register
del tuo AppServiceProvider
:
use App\Http\Middleware\TerminatingMiddleware;
/**
* Registra i servizi dell'applicazione.
*/
public function register(): void
{
$this->app->singleton(TerminatingMiddleware::class);
}