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
Sessioni
- Introduzione
- Interagire con la Sessione
- Blocca Sessione
- Aggiungere Driver di Sessione Personalizzati
Introduzione
Poiché le applicazioni basate su HTTP sono senza stato, le sessioni offrono un modo per memorizzare informazioni sull’utente attraverso più richieste. Queste informazioni sull’utente vengono solitamente salvate in un archivio persistente / backend a cui è possibile accedere nelle richieste successive.
Laravel include una varietà di backend per le sessioni accessibili tramite un’API espressiva e unificata. È incluso il supporto per backend popolari come Memcached, Redis e database.
Configurazione
Il file di configurazione delle sessioni della tua applicazione si trova in config/session.php
. Assicurati di esaminare le opzioni disponibili in questo file. Per impostazione predefinita, Laravel è configurato per utilizzare il driver delle sessioni database
.
L’opzione di configurazione driver
delle sessioni definisce dove i dati delle sessioni verranno memorizzati per ogni richiesta. Laravel include una varietà di driver:
-
file
– le sessioni sono memorizzate instorage/framework/sessions
. -
cookie
– le sessioni sono memorizzate in cookie sicuri e criptati. -
database
– le sessioni sono memorizzate in un database relazionale. -
memcached
/redis
– le sessioni sono memorizzate in uno di questi store veloci basati su cache. -
dynamodb
– le sessioni sono memorizzate in AWS DynamoDB. -
array
– le sessioni sono memorizzate in un array PHP e non saranno persistenti.
Il driver array è principalmente utilizzato durante il testing e impedisce la persistenza dei dati memorizzati nella sessione.
Prerequisiti per il driver
Database
Quando si utilizza il session driver database
, è necessario assicurarsi di avere una tabella nel database per contenere i dati della sessione. Tipicamente, questo è incluso nella migrazione di default di Laravel 0001_01_01_000000_create_users_table.php
database migration; tuttavia, se per qualche motivo non si dispone di una tabella sessions
, è possibile utilizzare il comando Artisan make:session-table
per generare questa migrazione:
php artisan make:session-table
php artisan migrate
Redis
Prima di utilizzare le sessioni Redis con Laravel, devi installare l’estensione PHP PhpRedis tramite PECL o installare il pacchetto predis/predis
(~1.0) tramite Composer. Per ulteriori informazioni sulla configurazione di Redis, consulta la documentazione Redis di Laravel.
La variabile d’ambiente
SESSION_CONNECTION
, oppure l’opzioneconnection
nel file di configurazionesession.php
, possono essere usate per specificare quale connessione Redis utilizzare per l’archiviazione delle sessioni.
Interagire con la Sessione
Recupero dei Dati
In Laravel ci sono due modi principali per lavorare con i dati della sessione: l’helper globale session
e tramite un’istanza di Request
. Innanzitutto, vediamo come accedere alla sessione tramite un’istanza di Request
, che può essere tipizzata in una closure di una route o in un metodo del controller. Ricorda, le dipendenze dei metodi del controller vengono automaticamente iniettate tramite il service container di Laravel:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\View\View;
class UserController extends Controller
{
/**
* Mostra il profilo dell'utente specificato.
*/
public function show(Request $request, string $id): View
{
$value = $request->session()->get('key');
// ...
$user = $this->users->find($id);
return view('user.profile', ['user' => $user]);
}
}
Quando recuperi un elemento dalla sessione, puoi anche passare un valore di default come secondo argomento al metodo get
. Questo valore di default verrà restituito se la chiave specificata non esiste nella sessione. Se passi una closure come valore di default al metodo get
e la chiave richiesta non esiste, la closure verrà eseguita e il suo risultato sarà restituito:
$value = $request->session()->get('key', 'default');
$value = $request->session()->get('key', function () {
return 'default';
});
L’Helper Session Globale
Puoi anche usare la funzione PHP globale session
per recuperare e memorizzare dati nella sessione. Quando l’helper session
viene chiamato con un solo argomento di tipo stringa, restituirà il valore di quella chiave nella sessione. Quando l’helper viene chiamato con un array di coppie chiave/valore, quei valori saranno memorizzati nella sessione:
Route::get('/home', function () {
// Recupera un dato dalla sessione...
$value = session('key');
// Specifica un valore di default...
$value = session('key', 'default');
// Memorizza un dato nella sessione...
session(['key' => 'value']);
});
C’è poca differenza pratica tra usare la sessione tramite un’istanza di richiesta HTTP o usare l’helper globale
session
. Entrambi i metodi sono testabili tramite il metodoassertSessionHas
disponibile in tutti i tuoi casi di test.
Recuperare Tutti i Dati della Sessione
Se desideri ottenere tutti i dati nella sessione, puoi usare il metodo all
:
$data = $request->session()->all();
Recuperare una Parte dei Dati di Sessione
I metodi only
ed except
possono essere usati per ottenere un sottoinsieme dei dati della sessione:
$data = $request->session()->only(['username', 'email']);
$data = $request->session()->except(['username', 'email']);
Determinare se un elemento esiste nella sessione
Per verificare se un elemento è presente nella sessione, puoi usare il metodo has
. Il metodo has
restituisce true
se l’elemento è presente e non è null
:
if ($request->session()->has('users')) {
// ...
}
Per verificare se un elemento è presente nella sessione, anche se il suo valore è null
, puoi usare il metodo exists
:
if ($request->session()->exists('users')) {
// ...
}
Per verificare se un elemento non è presente nella sessione, puoi usare il metodo missing
. Il metodo missing
restituisce true
se l’elemento non è presente:
if ($request->session()->missing('users')) {
// ...
}
Memorizzare Dati
Per memorizzare dati nella sessione, solitamente usi il metodo put
dell’istanza request
oppure l’helper globale session
:
// Tramite un'istanza request...
$request->session()->put('key', 'value');
// Tramite l'helper globale "session"...
session(['key' => 'value']);
Aggiungere Valori a un Array nella Sessione
Il metodo push
può essere utilizzato per aggiungere un nuovo valore a una sessione che è un array. Ad esempio, se la chiave user.teams
contiene un array di nomi di team, puoi aggiungere un nuovo valore all’array in questo modo:
$request->session()->push('user.teams', 'developers');
Recuperare e Cancellare un Elemento
Il metodo pull
recupera e cancella un elemento dalla sessione in un’unica istruzione:
$value = $request->session()->pull('key', 'default');
Incremento e Decremento dei Valori di Sessione
Se i dati della tua sessione contengono un intero che desideri incrementare o decrementare, puoi utilizzare i metodi increment
e decrement
:
$request->session()->increment('count');
$request->session()->increment('count', $incrementBy = 2);
$request->session()->decrement('count');
$request->session()->decrement('count', $decrementBy = 2);
Dati Flash
A volte potresti voler memorizzare elementi nella sessione per la richiesta successiva. Puoi farlo usando il metodo flash
. I dati memorizzati nella sessione con questo metodo saranno disponibili subito e durante la richiesta HTTP successiva. Dopo la richiesta HTTP successiva, i dati flash verranno eliminati. I dati flash sono principalmente utili per messaggi di stato a breve termine:
$request->session()->flash('status', 'Task was successful!');
Se hai bisogno di mantenere i tuoi dati flash per più richieste, puoi usare il metodo reflash
, che conserverà tutti i dati flash per una richiesta aggiuntiva. Se devi mantenere solo dati flash specifici, puoi usare il metodo keep
:
$request->session()->reflash();
$request->session()->keep(['username', 'email']);
Per mantenere i tuoi dati flash solo per la richiesta corrente, puoi usare il metodo `now`:
$request->session()->now('status', 'Task was successful!')
Cancellare i Dati
Il metodo forget
rimuove un dato dalla sessione. Se vuoi eliminare tutti i dati dalla sessione, puoi usare il metodo flush
:
// Rimuovi una singola chiave...
$request->session()->forget('name');
// Rimuovi più chiavi...
$request->session()->forget(['name', 'status']);
$request->session()->flush();
Rigenerare l’ID della Sessione
Rigenerare l’ID della sessione è spesso fatto per prevenire che utenti malintenzionati sfruttino un attacco di session fixation sulla tua applicazione.
Laravel rigenera automaticamente l’ID della sessione durante l’autenticazione se stai usando uno dei starter kit di applicazione di Laravel o Laravel Fortify; tuttavia, se hai bisogno di rigenerare manualmente l’ID della sessione, puoi usare il metodo regenerate
:
$request->session()->regenerate();
Se hai bisogno di rigenerare l’ID della sessione e rimuovere tutti i dati dalla sessione in un’unica istruzione, puoi usare il metodo invalidate
:
$request->session()->invalidate()
Blocca Sessione
Per utilizzare il blocco della sessione, la tua applicazione deve utilizzare un cache driver che supporta i blocchi atomici. Attualmente, questi cache driver includono
memcached
,dynamodb
,redis
,mongodb
(incluso nel pacchetto ufficialemongodb/laravel-mongodb
),database
,file
earray
. Inoltre, non puoi usare il driver di sessionecookie
.
Per impostazione predefinita, Laravel permette alle richieste che utilizzano la stessa sessione di eseguire concorrentemente. Quindi, per esempio, se usi una libreria HTTP JavaScript per fare due richieste HTTP alla tua applicazione, si eseguiranno entrambe allo stesso tempo. Per molte applicazioni, questo non è un problema; tuttavia, la perdita di dati della sessione può verificarsi in un piccolo sottoinsieme di applicazioni che effettuano richieste concorrenti a due endpoint dell’applicazione differenti che scrivono entrambe dati nella sessione.
Per mitigare questo, Laravel fornisce una funzionalità che permette di limitare le richieste concorrenti per una determinata sessione. Per iniziare, puoi semplicemente concatenare il metodo block
alla definizione della tua rotta. In questo esempio, una richiesta in arrivo all’endpoint /profile
acquisirà un blocco della sessione. Mentre questo blocco è attivo, qualsiasi richiesta in arrivo agli endpoint /profile
o /order
che condividono lo stesso ID di sessione aspetterà che la prima richiesta finisca di eseguire prima di continuare la loro esecuzione:
Route::post('/profile', function () {
// ...
})->block($lockSeconds = 10, $waitSeconds = 10)
Route::post('/order', function () {
// ...
})->block($lockSeconds = 10, $waitSeconds = 10)
Il metodo block
accetta due argomenti opzionali. Il primo argomento accettato dal metodo block
è il numero massimo di secondi per cui il blocco della sessione deve essere mantenuto prima di essere rilasciato. Naturalmente, se la richiesta finisce di eseguire prima di questo tempo, il blocco verrà rilasciato prima.
Il secondo argomento accettato dal metodo block
è il numero di secondi che una richiesta deve attendere mentre tenta di ottenere un blocco della sessione. Verrà lanciata un’eccezione Illuminate\Contracts\Cache\LockTimeoutException
se la richiesta non riesce a ottenere un blocco della sessione entro il numero di secondi specificato.
Se nessuno di questi argomenti viene passato, il blocco verrà ottenuto per un massimo di 10 secondi e le richieste attenderanno al massimo 10 secondi mentre tentano di ottenere un blocco:
Route::post('/profile', function () {
// ...
})->block()
Aggiungere Driver di Sessione Personalizzati
Implementazione del Driver
Se nessuno dei driver di sessione esistenti soddisfa le esigenze della tua applicazione, Laravel permette di scrivere il proprio gestore di sessioni. Il tuo driver di sessione personalizzato dovrebbe implementare l’interfaccia integrata di PHP SessionHandlerInterface
. Questa interfaccia contiene solo alcuni metodi semplici. Un’implementazione di esempio per MongoDB appare come segue:
<?php
namespace App\Extensions;
class MongoSessionHandler implements \SessionHandlerInterface
{
public function open($savePath, $sessionName) {}
public function close() {}
public function read($sessionId) {}
public function write($sessionId, $data) {}
public function destroy($sessionId) {}
public function gc($lifetime) {}
}
Poiché Laravel non include una directory predefinita per ospitare le tue estensioni, sei libero di posizionarle dove preferisci. In questo esempio, abbiamo creato una directory Extensions
per contenere il MongoSessionHandler
.
Poiché lo scopo di questi metodi non è immediatamente comprensibile, ecco una panoramica dello scopo di ciascun metodo:
- Il metodo
open
viene tipicamente usato nei sistemi di memorizzazione delle sessioni basati su file. Poiché Laravel include un driver di sessionefile
, raramente sarà necessario inserire qualcosa in questo metodo. Puoi semplicemente lasciare questo metodo vuoto. - Il metodo
close
, come il metodoopen
, di solito può essere ignorato. Per la maggior parte dei driver, non è necessario. - Il metodo
read
dovrebbe restituire la versione in stringa dei dati della sessione associata al dato$sessionId
. Non è necessario eseguire alcuna serializzazione o altra codifica quando si recuperano o si memorizzano i dati della sessione nel tuo driver, poiché Laravel si occuperà della serializzazione per te. - Il metodo
write
dovrebbe scrivere la stringa$data
fornita associata al$sessionId
in un sistema di memorizzazione persistente, come MongoDB o un altro sistema di archiviazione a tua scelta. Anche in questo caso, non dovresti eseguire alcuna serializzazione – Laravel se ne avrà già occupato. - Il metodo
destroy
dovrebbe rimuovere i dati associati al$sessionId
dalla memorizzazione persistente. - Il metodo
gc
dovrebbe distruggere tutti i dati della sessione che sono più vecchi del dato$lifetime
, che è un timestamp UNIX. Per sistemi a scadenza automatica come Memcached e Redis, questo metodo può essere lasciato vuoto.
Registrazione del Driver
Una volta implementato il tuo driver, sei pronto per registrarlo con Laravel. Per aggiungere driver aggiuntivi al backend delle sessioni di Laravel, puoi utilizzare il metodo extend
fornito dalla facade Session
. Dovresti chiamare il metodo extend
dal metodo boot
di un service provider. Puoi farlo dal provider esistente App\Providers\AppServiceProvider
o creare un provider completamente nuovo:
<?php
namespace App\Providers;
use App\Extensions\MongoSessionHandler;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;
class SessionServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ...
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Session::extend('mongo', function (Application $app) {
// Return an implementation of SessionHandlerInterface...
return new MongoSessionHandler;
});
}
}
Una volta registrato il driver delle sessioni, puoi specificare il driver mongo
come driver delle sessioni della tua applicazione utilizzando la variabile d’ambiente SESSION_DRIVER
o nel file di configurazione config/session.php
dell’applicazione.