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
Sanctum
- Introduzione
- Installazione
- Configurazione
- Autenticazione tramite Token API
- Autenticazione per SPA
- Autenticazione per Applicazioni Mobile
- Test
Introduzione
Laravel Sanctum offre un sistema di autenticazione leggero per SPAs (applicazioni a pagina singola), applicazioni mobili e semplici API basate su token. Sanctum permette a ogni utente della tua applicazione di generare più token API per il proprio account. Questi token possono avere abilità / scope che specificano quali azioni i token possono eseguire.
Come Funziona
Laravel Sanctum esiste per risolvere due problemi distinti. Discutiamo ciascuno prima di approfondire la libreria.
API Tokens
Sanctum è un pacchetto semplice che puoi usare per emettere token API ai tuoi utenti senza la complicazione di OAuth. Questa funzionalità è ispirata da GitHub e altre applicazioni che emettono "personal access tokens". Per esempio, immagina che le "impostazioni dell’account" della tua applicazione abbiano una schermata dove un utente può generare un token API per il proprio account. Puoi usare Sanctum per generare e gestire questi token. Questi token di solito hanno un tempo di scadenza molto lungo (anni), ma possono essere revocati manualmente dall’utente in qualsiasi momento.
Laravel Sanctum offre questa funzionalità memorizzando i token API degli utenti in una singola tabella del database e autenticando le richieste HTTP in arrivo tramite l’intestazione Authorization
che deve contenere un token API valido.
Autenticazione SPA
In secondo luogo, Sanctum offre un modo semplice per autenticare le single page applications (SPA) che devono comunicare con un’API basata su Laravel. Queste SPA possono trovarsi nello stesso repository della tua applicazione Laravel o in un repository completamente separato, come una SPA creata con Next.js o Nuxt.
Per questa funzionalità, Sanctum non utilizza token di alcun tipo. Al suo posto, Sanctum utilizza i servizi di autenticazione delle sessioni basati su cookie di Laravel. Tipicamente, Sanctum utilizza la guardia di autenticazione web
di Laravel per ottenere questo risultato. Questo fornisce i vantaggi della protezione CSRF, dell’autenticazione delle sessioni e protegge contro la perdita delle credenziali di autenticazione tramite XSS.
Sanctum tenterà di autenticarsi usando i cookie solo quando la richiesta in arrivo proviene dal tuo front-end SPA. Quando Sanctum esamina una richiesta HTTP in arrivo, controllerà prima la presenza di un cookie di autenticazione e, se non è presente, esaminerà l’intestazione Authorization
per un token API valido.
È perfettamente valido usare Sanctum solo per l’autenticazione con token API o solo per l’autenticazione SPA. Usare Sanctum non significa che devi utilizzare entrambe le funzionalità che offre.
Installazione
Puoi installare Laravel Sanctum tramite il comando Artisan install:api
:
php artisan install:api
Successivamente, se intendi utilizzare Sanctum per autenticare una SPA, consulta la sezione SPA Authentication di questa documentazione.
Configurazione
Sostituzione dei Modelli Predefiniti
Anche se normalmente non è necessario, puoi estendere il modello PersonalAccessToken
utilizzato internamente da Sanctum:
use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;
class PersonalAccessToken extends SanctumPersonalAccessToken
{
// ...
}
Successivamente, puoi dire a Sanctum di usare il tuo modello personalizzato tramite il metodo usePersonalAccessTokenModel
fornito da Sanctum. Di solito, dovresti chiamare questo metodo nel metodo boot
del file AppServiceProvider
della tua applicazione:
use App\Models\Sanctum\PersonalAccessToken;
use Laravel\Sanctum\Sanctum;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
}
Autenticazione tramite Token API
Non dovresti usare i token API per autenticare la tua prima-party SPA. Usa invece le funzionalità di autenticazione SPA integrate in Sanctum.
Emissione di Token API
Sanctum ti permette di emettere token API / token di accesso personali che possono essere usati per autenticare le richieste API alla tua applicazione. Quando effettui richieste usando token API, il token deve essere incluso nell’intestazione Authorization
come token Bearer
.
Per iniziare a emettere token per gli utenti, il tuo modello User dovrebbe usare il trait Laravel\Sanctum\HasApiTokens
:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
Per emettere un token, puoi usare il metodo createToken
. Il metodo createToken
restituisce un’istanza di Laravel\Sanctum\NewAccessToken
. I token API vengono hashati con SHA-256 prima di essere memorizzati nel tuo database, ma puoi accedere al valore in chiaro del token usando la proprietà plainTextToken
dell’istanza NewAccessToken
. Dovresti mostrare questo valore all’utente subito dopo che il token è stato creato:
use Illuminate\Http\Request;
Route::post('/tokens/create', function (Request $request) {
$token = $request->user()->createToken($request->token_name);
return ['token' => $token->plainTextToken];
});
Puoi accedere a tutti i token dell’utente usando la relazione Eloquent tokens
fornita dal trait HasApiTokens
:
foreach ($user->tokens as $token) {
// ...
}
Abilità del Token
Sanctum ti permette di assegnare "abilità" ai token. Le abilità hanno uno scopo simile ai "scope" di OAuth. Puoi passare un array di abilità come stringhe come secondo argomento al metodo createToken
:
return $user->createToken('token-name', ['server:update'])->plainTextToken;
Quando gestisci una richiesta in arrivo autenticata da Sanctum, puoi verificare se il token ha una determinata abilità usando i metodi tokenCan
o tokenCant
:
if ($user->tokenCan('server:update')) {
// ...
}
if ($user->tokenCant('server:update')) {
// ...
}
Middleware di Abilità dei Token
Sanctum include anche due middleware che possono essere utilizzati per verificare che una richiesta in arrivo sia autenticata con un token che ha ricevuto una determinata abilità. Per iniziare, definisci i seguenti alias di middleware nel file bootstrap/app.php
della tua applicazione:
use Laravel\Sanctum\Http\Middleware\CheckAbilities;
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'abilities' => CheckAbilities::class,
'ability' => CheckForAnyAbility::class,
]);
})
Il middleware abilities
può essere assegnato a una rotta per verificare che il token della richiesta in arrivo abbia tutte le abilità elencate:
Route::get('/orders', function () {
// Il token ha sia le abilità "check-status" che "place-orders"...
})->middleware(['auth:sanctum', 'abilities:check-status,place-orders']);
Il middleware ability
può essere assegnato a una rotta per verificare che il token della richiesta in arrivo abbia almeno una delle abilità elencate:
Route::get('/orders', function () {
// Il token ha l'abilità "check-status" o "place-orders"...
})->middleware(['auth:sanctum', 'ability:check-status,place-orders']);
Richieste Innescate dall’Interfaccia Utente First-Party
Per comodità, il metodo tokenCan
restituirà sempre true
se la richiesta autenticata in ingresso proviene dalla tua SPA di prima parte e stai utilizzando l’autenticazione SPA integrata di Sanctum.
Tuttavia, ciò non significa necessariamente che la tua applicazione debba permettere all’utente di eseguire l’azione. Tipicamente, le politiche di autorizzazione della tua applicazione determineranno se al token sono state concesse le autorizzazioni per eseguire le azioni, oltre a verificare che l’istanza dell’utente stessa possa effettuare l’azione.
Ad esempio, se immaginiamo un’applicazione che gestisce server, questo potrebbe significare verificare che il token sia autorizzato ad aggiornare i server e che il server appartenga all’utente:
return $request->user()->id === $server->user_id &&
$request->user()->tokenCan('server:update')
All’inizio, permettere che il metodo tokenCan
venga chiamato e restituisca sempre true
per le richieste innescate dall’UI di prima parte può sembrare strano; tuttavia, è comodo poter sempre presumere che un token API sia disponibile e possa essere esaminato tramite il metodo tokenCan
. Adottando questo approccio, puoi sempre chiamare il metodo tokenCan
all’interno delle politiche di autorizzazione della tua applicazione senza preoccuparti se la richiesta è stata generata dall’UI della tua applicazione o è stata innescata da uno dei consumatori di terze parti della tua API.
Proteggere le Rotte
Per fare in modo che tutte le richieste alle rotte siano autenticate, devi utilizzare la guardia di autenticazione sanctum
nelle tue rotte protette nei file routes/web.php
e routes/api.php
. Questa guardia garantirà che le richieste in arrivo siano autenticate come richieste con stato tramite cookie o che contengano un’intestazione di token API valida se la richiesta proviene da una terza parte.
Potresti chiederti perché suggeriamo di autenticare le rotte nel file routes/web.php
della tua applicazione usando la guardia sanctum
. Ricorda che Sanctum proverà prima ad autenticare le richieste in arrivo utilizzando il normale cookie di autenticazione della sessione di Laravel. Se quel cookie non è presente, Sanctum tenterà di autenticare la richiesta usando un token nell’intestazione Authorization
della richiesta. Inoltre, autenticare tutte le richieste con Sanctum assicura che possiamo sempre utilizzare il metodo tokenCan
sull’istanza utente attualmente autenticata:
use Illuminate\Http\Request;
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
Revoca dei Token
Puoi "revocare" i token eliminandoli dal tuo database utilizzando la relazione tokens
fornita dal trait Laravel\Sanctum\HasApiTokens
:
// Revoca tutti i token...
$user->tokens()->delete();
// Revoca il token utilizzato per autenticare la richiesta corrente...
$request->user()->currentAccessToken()->delete();
// Revoca un token specifico...
$user->tokens()->where('id', $tokenId)->delete();
Scadenza dei Token
Per impostazione predefinita, i token di Sanctum non scadono mai e possono essere invalidati solo revocando il token. Tuttavia, se desideri configurare un tempo di scadenza per i token API della tua applicazione, puoi farlo tramite l’opzione di configurazione expiration
definita nel file di configurazione sanctum
della tua applicazione. Questa opzione di configurazione definisce il numero di minuti dopo i quali un token emesso sarà considerato scaduto:
'expiration' => 525600,
Se desideri specificare il tempo di scadenza di ogni token in modo indipendente, puoi farlo fornendo il tempo di scadenza come terzo argomento al metodo createToken
:
return $user->createToken(
'token-name', ['*'], now()->addWeek()
)->plainTextToken;
Se hai configurato un tempo di scadenza dei token per la tua applicazione, potresti anche voler programmare un’attività per eliminare i token scaduti della tua applicazione. Fortunatamente, Sanctum include un comando Artisan sanctum:prune-expired
che puoi utilizzare per realizzare questo. Ad esempio, puoi configurare un’attività programmata per eliminare tutti i record dei token scaduti nel database che sono scaduti da almeno 24 ore:
use Illuminate\Support\Facades\Schedule;
Schedule::command('sanctum:prune-expired --hours=24')->daily();
Autenticazione per SPA
Sanctum esiste anche per fornire un metodo semplice per autenticare le single page applications (SPA) che devono comunicare con un’API basata su Laravel. Queste SPA possono trovarsi nello stesso repository della tua applicazione Laravel oppure in un repository completamente separato.
Per questa funzionalità, Sanctum non utilizza token di alcun tipo. Invece, Sanctum utilizza i servizi di autenticazione delle sessioni basate su cookie integrati in Laravel. Questo approccio all’autenticazione offre i vantaggi della protezione CSRF, dell’autenticazione di sessione e protegge anche dalla diffusione delle credenziali di autenticazione tramite XSS.
Per autenticare, la tua SPA e l’API devono condividere lo stesso dominio di primo livello. Tuttavia, possono essere posizionate su sottodomini diversi. Inoltre, dovresti assicurarti di inviare l’header
Accept: application/json
e l’headerReferer
oOrigin
con la tua richiesta.
Configurazione
Configurare i Tuoi Domini di Prima Parte
Per prima cosa, dovresti configurare da quali domini la tua SPA effettuerà le richieste. Puoi configurare questi domini utilizzando l’opzione di configurazione stateful
nel tuo file di configurazione sanctum
. Questa impostazione determina quali domini manterranno un’autenticazione "stateful" utilizzando i cookie di sessione di Laravel quando effettuano richieste alla tua API.
Se stai accedendo alla tua applicazione tramite un URL che include una porta (
127.0.0.1:8000
), dovresti assicurarti di includere il numero della porta con il dominio.
Middleware di Sanctum
Successivamente, dovresti istruire Laravel affinché le richieste in arrivo dalla tua SPA possano autenticarsi utilizzando i cookie di sessione di Laravel, permettendo allo stesso tempo alle richieste di terze parti o alle applicazioni mobili di autenticarsi usando i token API. Questo può essere facilmente ottenuto invocando il metodo statefulApi
nel file bootstrap/app.php
della tua applicazione:
->withMiddleware(function (Middleware $middleware) {
$middleware->statefulApi();
})
CORS e Cookie
Se hai problemi ad autenticarti con la tua applicazione da una SPA che opera su un sottodominio separato, probabilmente hai configurato in modo errato le impostazioni CORS (Cross-Origin Resource Sharing) o i cookie di sessione.
Il file di configurazione config/cors.php
non viene pubblicato di default. Se hai bisogno di personalizzare le opzioni CORS di Laravel, dovresti pubblicare il file di configurazione completo cors
usando il comando Artisan config:publish
:
php artisan config:publish cors
Successivamente, devi assicurarti che la configurazione CORS della tua applicazione restituisca l’intestazione Access-Control-Allow-Credentials
con un valore di True
. Questo può essere fatto impostando l’opzione supports_credentials
nel file di configurazione config/cors.php
della tua applicazione su true
.
Inoltre, dovresti abilitare le opzioni withCredentials
e withXSRFToken
sull’istanza globale axios
della tua applicazione. Tipicamente, questo dovrebbe essere fatto nel file resources/js/bootstrap.js
. Se non stai utilizzando Axios per fare richieste HTTP dal frontend, dovresti effettuare la configurazione equivalente sul tuo client HTTP personalizzato:
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
Infine, devi assicurarti che la configurazione del dominio dei cookie di sessione della tua applicazione supporti qualsiasi sottodominio del tuo dominio principale. Puoi farlo aggiungendo un prefisso .
al dominio nel file di configurazione config/session.php
della tua applicazione:
'domain' => '.domain.com',
Autenticazione
Protezione CSRF
Per autenticare la tua SPA, la pagina di "login" della tua SPA dovrebbe prima effettuare una richiesta all’endpoint /sanctum/csrf-cookie
per inizializzare la protezione CSRF per l’applicazione:
axios.get('/sanctum/csrf-cookie').then(response => {
// Login...
});
Durante questa richiesta, Laravel imposterà un cookie XSRF-TOKEN
contenente il token CSRF attuale. Questo token deve poi essere inviato nell’intestazione X-XSRF-TOKEN
nelle richieste successive, cosa che alcune librerie client HTTP come Axios e l’Angular HttpClient fanno automaticamente per te. Se la tua libreria HTTP JavaScript non imposta il valore per te, dovrai impostare manualmente l’intestazione X-XSRF-TOKEN
per corrispondere al valore del cookie XSRF-TOKEN
impostato da questa rotta.
Accesso
Una volta che la protezione CSRF è stata inizializzata, dovresti effettuare una richiesta POST
alla rotta /login
della tua applicazione Laravel. Questa rotta /login
può essere implementata manualmente o utilizzando un pacchetto di autenticazione headless come Laravel Fortify.
Se la richiesta di accesso ha successo, sarai autenticato e le richieste successive alle rotte della tua applicazione saranno automaticamente autenticate tramite il cookie di sessione che l’applicazione Laravel ha emesso al tuo client. Inoltre, poiché la tua applicazione ha già effettuato una richiesta alla rotta /sanctum/csrf-cookie
, le richieste successive dovrebbero automaticamente ricevere la protezione CSRF, a condizione che il tuo client HTTP JavaScript invii il valore del cookie XSRF-TOKEN
nell’intestazione X-XSRF-TOKEN
.
Naturalmente, se la sessione dell’utente scade per inattività, le richieste successive all’applicazione Laravel potrebbero ricevere una risposta di errore HTTP 401 o 419. In questo caso, dovresti reindirizzare l’utente alla pagina di accesso della tua SPA.
Sei libero di scrivere il tuo endpoint
/login
; tuttavia, dovresti assicurarti che autentichi l’utente utilizzando i servizi di autenticazione basati su sessione standard che Laravel fornisce, come descritto nella documentazione. Tipicamente, questo significa utilizzare la guardia di autenticazioneweb
.
Protezione delle Rotte
Per proteggere le rotte in modo che tutte le richieste in arrivo siano autenticate, devi associare la guardia di autenticazione sanctum
alle tue rotte API nel file routes/api.php
. Questa guardia garantirà che le richieste in arrivo siano autenticate come richieste con stato dalla tua SPA oppure contengano un header di token API valido se la richiesta proviene da una terza parte:
use Illuminate\Http\Request;
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
Autorizzazione dei Canali Broadcast Privati
Se la tua SPA deve autenticarsi con canali broadcast privati / di presenza, dovresti rimuovere l’elemento channels
dal metodo withRouting
presente nel file bootstrap/app.php
della tua applicazione. Invece, dovresti invocare il metodo withBroadcasting
per specificare il middleware corretto per le rotte di broadcasting della tua applicazione:
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
// ...
)
->withBroadcasting(
__DIR__.'/../routes/channels.php',
['prefix' => 'api', 'middleware' => ['api', 'auth:sanctum']],
)
Successivamente, affinché le richieste di autorizzazione di Pusher abbiano successo, dovrai fornire un authorizer
personalizzato di Pusher durante l’inizializzazione di Laravel Echo. Questo permette alla tua applicazione di configurare Pusher per utilizzare l’istanza di axios
che è correttamente configurata per le richieste cross-domain:
window.Echo = new Echo({
broadcaster: "pusher",
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
encrypted: true,
key: import.meta.env.VITE_PUSHER_APP_KEY,
authorizer: (channel, options) => {
return {
authorize: (socketId, callback) => {
axios.post('/api/broadcasting/auth', {
socket_id: socketId,
channel_name: channel.name
})
.then(response => {
callback(false, response.data);
})
.catch(error => {
callback(true, error);
});
}
};
},
})
Autenticazione per Applicazioni Mobile
Puoi anche utilizzare i token Sanctum per autenticare le richieste della tua applicazione mobile alla tua API. Il processo di autenticazione delle richieste dell’applicazione mobile è simile all’autenticazione delle richieste API di terze parti; tuttavia, ci sono piccole differenze nel modo in cui emetterai i token API.
Emissione dei Token API
Per iniziare, crea una route che accetti l’email o il nome utente dell’utente, la password e il nome del dispositivo, quindi scambia queste credenziali per un nuovo token Sanctum. Il "device name" fornito a questo endpoint è solo a scopo informativo e può essere qualsiasi valore desideri. In generale, il device name dovrebbe essere un nome riconoscibile dall’utente, come "iPhone 12 di Nuno".
Di solito, effettuerai una richiesta all’endpoint del token dalla schermata di "login" della tua applicazione mobile. L’endpoint restituirà il token API in chiaro, che potrà essere memorizzato sul dispositivo mobile e utilizzato per effettuare ulteriori richieste API:
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
Route::post('/sanctum/token', function (Request $request) {
$request->validate([
'email' => 'required|email',
'password' => 'required',
'device_name' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['Le credenziali fornite non sono corrette.'],
]);
}
return $user->createToken($request->device_name)->plainTextToken;
});
Quando l’applicazione mobile utilizza il token per effettuare una richiesta API alla tua applicazione, deve inviare il token nell’intestazione Authorization
come token Bearer
.
Quando emetti token per un’applicazione mobile, puoi anche specificare token abilities.
Proteggere le Rotte
Come documentato in precedenza, puoi proteggere le rotte in modo che tutte le richieste in arrivo debbano essere autenticate associando la guardia di autenticazione sanctum
alle rotte:
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
Revocare i Token
Per permettere agli utenti di revocare i token API emessi ai dispositivi mobili, puoi elencarli per nome, insieme a un pulsante "Revoca", nella sezione "impostazioni account" dell’interfaccia della tua applicazione web. Quando l’utente clicca sul pulsante "Revoca", puoi eliminare il token dal database. Ricorda, puoi accedere ai token API di un utente tramite la relazione tokens
fornita dal trait Laravel\Sanctum\HasApiTokens
:
// Revoca tutti i token...
$user->tokens()->delete();
// Revoca un token specifico...
$user->tokens()->where('id', $tokenId)->delete();
Test
Durante i test, il metodo Sanctum::actingAs
può essere utilizzato per autenticare un utente e specificare quali abilità dovrebbero essere concesse al suo token:
use App\Models\User;
use Laravel\Sanctum\Sanctum;
test('task list can be retrieved', function () {
Sanctum::actingAs(
User::factory()->create(),
['view-tasks']
);
$response = $this->get('/api/task');
$response->assertOk();
});
use App\Models\User;
use Laravel\Sanctum\Sanctum;
public function test_task_list_can_be_retrieved(): void
{
Sanctum::actingAs(
User::factory()->create(),
['view-tasks']
);
$response = $this->get('/api/task');
$response->assertOk();
}
Se desideri concedere tutte le abilità al token, dovresti includere *
nell’elenco delle abilità fornito al metodo actingAs
:
Sanctum::actingAs(
User::factory()->create(),
['*']
);