CONTATTACI

Guide per aspiranti programmatori

developer con in maon una scatola da cui escono delle sfere gialle
Lezione 24 / 30

Autenticazione in Laravel

In un applicativo web è importante poter distinguere quali richieste sono effettuate da utenti registrati e quali, invece, provengono da visitatori che non hanno fatto l’accesso. A seconda dei casi, infatti, potremmo voler concedere solo ad alcuni l’accesso a determinate risorse (per esempio solo gli utenti registrati come “editor” possono aggiungere nuovi post a un blog) oppure voler mostrare solo determinati elementi di proprietà dell’utente registrate (per esempio la pagina “Ordini” dovrebbe mostrare solo i miei ordini, non quelli di tutti gli utenti del sito di e-commerce).

Laravel offre una gestione dell’autenticazione completa e flessibile, capace di adattarsi a varie necessità e implementazioni.

In questa lezione, vedremo alcuni concetti generali e una implementazione d’esempio tramite middleware per un’applicazione web che segue il paradigma MVC.

Guards e Providers in Laravel

In Laravel le funzionalità legate all’autenticazione si basano sulla configurazione di due diverse informazioni:

  • guard – definisce come stabilire se una richiesta HTTP ricevuta è da una “utenza” autenticato
  • provider – definisce come recuperare gli utenti registrati per l’applicazione

Un’ applicazione Laravel appena creata fornisce una configurazione di guard e provider adatta alle esigenze di una applicazione che eroga solo pagine web e che gestisce interamente lato server la generazione del codice HTML. Infatti, risulta già attiva la guard session – che usa cookie di sessione per stabilire se la richiesta viene da un utente autenticato – e il provider fornito è già configurato per usare il database tramite Eloquent e, in particolare, il model App\Models\User.

Esistono situazioni in cui questa combinazione non è adatta. Ad esempio, il caso in cui l’applicazione Laravel offre delle API RESTful oppure in cui sia il backend di una Single Page Application. In questo caso, è necessario includere e configurare altri servizi di autenticazione offerti dall’ecosistema Laravel. Per esempio, nel caso del server di API, si dovrebbe optare per un guard di tipo token, che consente di riconoscere i client autenticati da uno specifico token presente nella richiesta.

In questa lezione vedremo la configurazione base di Laravel, che offrirà comunque molti spunti per comprendere come Laravel gestisce le richieste autenticate, indipendentemente dal guard e provider impostati.

Modello User come provider di utenti in Laravel

Quando creiamo una nuova applicazione Laravel vengono impostate una serie di configurazioni di default per gestire l’autenticazione.

Tali configurazioni sono definite nel file config/auth.php e ci dicono che il provider di utenti dell’applicazione è la tabella users accedibile tramite il modello App\Models\User di Eloquent.

composer create-project laravel/laravel example-app-auth

Non a caso, infatti, il model App\Models\User fornito in un nuovo progetto non estende direttamente la classe Model, ma la classe Illuminate\Foundation\Auth\User. Ciò permette di individuarlo come model adeguato per essere provider degli utenti dell’applicazione.

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
  protected $fillable = [
    'name',
    'email',
    'password',
  ];

  protected $hidden = [
    'password',
    'remember_token',
  ];
}

Possiamo, quindi, utilizzare questo model per creare il nostro form di registrazione self-service di nuovi utenti, sfruttando quanto messo già a disposizione da Laravel.

In questo modo, potremo verificare con mano come funzionano i vari meccanismi di autenticazione in un’ applicazione Laravel nei vari punti dello stack MVC.

Registrazione utenti in Laravel

Abbiamo visto, nella lezione sulla validazione degli input, come creare un form e utilizzarlo per inviare nuovi dati al nostro applicativo. Anche la registrazione di un nuovo utente segue uno schema simile. Dovremo, quindi, creare un nuovo form HTML in cui sia possibile inserire i dati da inserire nella tabella users tramite il model User.

Ci servono, quindi, un Controller e una View per poter creare una nuova istanza del model User.

Per il controller e le relative rotte possiamo procedere nel modo seguente, utilizzando le varie convenzioni viste nelle lezioni precedenti.

$ php artisan migrate

$ php artisan make:controller RegisterController

 INFO Controller [app/Http/Controllers/RegisterController.php] created successfully.
// app/Http/Controllers/RegisterController.php
class RegisterController extends Controller
{
  public function create()
  {
    return view('register.create');
  }

  public function store(Request $request)
  {
    $attributes = $request->validate([
      'name' => 'required',
      'email' => ['required', 'unique:users', 'email'],
      'password' => ['required'],
    ]);

    $user = User::create($attributes);

    // utente creato ... e ora?
  }
}

// routes/web.php
// ...
Route::get('/register', array(RegisterController::class, 'create'))->named;
Route::post('/register', array(RegisterController::class, 'store'));

Per la view potremo generare un template Blade resources/view/register/create.blade.php che contiene un form con gli input name, email e password e che effettui una POST /register con i dati del form.

{{-- resources/views/register/create.blade.php --}}
<div>
  <h1>Register a User</h1>
  <form action="/register" method="POST">
    @csrf
    <label for="name">Name</label>
    <input type="text" name="name" id="name">

    <label for="email">Email</label>
    <input type="text" name="email" id="email">

    <label for="password">Password</label>
    <input type="password" name="password" id="password">

    <button type="submit">REGISTER</button>
  </form>
</div>

Con queste poche modifiche siamo in grado di registrare un nuovo utente, cioè aggiungere una nuova riga alla tabella users.

NOTA: la password salvata in questi esempi è, ovviamente, in chiaro; nel caso di utilizzo reale va opportunamente modificato il proprio codice per salvare e poi utilizzare questa informazione in maniera sicura.

Avvio di una sessione alla registrazione e prima autenticazione in Laravel

Ora che abbiamo modo di creare nuovi utenti nel provider dell’authentication, occupiamoci di gestire la parte della guard.

Sappiamo che un’applicazione Laravel appena creata ha già attiva per le richieste di tipo web la guard di tipo session collegata al provider predefinito. In questa gestione dell’autenticazione, l’utente chiede di effettuare login via browser e, se tale login va a buon fine, il server crea un id univoco di sessione e lo rimanda al browser tramite cookie. Il browser potrà, quindi, usare tale cookie di sessione nelle seguenti richieste HTTP per indicare che si tratta dello stesso utente autenticato. Al logout, il cookie viene rimosso e lato server viene cancellato l’id di sessione.

Per creare una nuova sessione nella nostra applicazione d’esempio, possiamo intervenire subito dopo il salvataggio della nuova utenza a database e fare in modo che venga fatta far partire la sessione dell’utente appena registrato.

Nelle applicazioni Laravel viene in aiuto il metodo helper auth() – o l’analoga facade Auth – che ci consente di intervenire su tutto ciò che è relativo alle sessioni autenticate.

Possiamo, quindi, cambiare il nostro controller RegisterController nel modo seguente

public function store(Request $request)
  {
    $attributes = $request->validate([
      'name' => 'required',
      'email' => ['required', 'unique:users', 'email'],
      'password' => ['required'],
    ]);

    $user = User::create($attributes);

    // qui viene effettuata l'autenticazione e creata la sessione
    auth()->login($user);

    // qui viene creata la risposta che contiene il cookie di sessione appena creata
    return redirect('/');
  }

L’helper auth di Laravel ci permette di operare in modo trasparente sia con i provider di utenti che con le guard.

Saranno direttamente le varie implementazioni sottostanti del framework Laravel a sapere che l’istanza $user è collegata al provider degli utenti e a occuparsi di creare la sessione e il relativo cookie da aggiungere, in modo da considerare come autenticate le future richieste provenienti da quel browser.

Individuare sessioni autenticate nei controller e nelle view in Laravel

Le richieste HTTP provenienti da un client che ha completato con successo l’autenticazione possono essere individuate in vari punti dello stack MVC di Laravel. Ciò consente di intervenire nei modi opportuni per impedire o modificare determinati comportamenti.

Ad esempio, un utente autenticato non dovrebbe accedere alla pagina di registrazione. Laravel permette di indicare quali rotte devono essere mostrate agli utenti autenticati e quali ai visitatori tramite l’uso dei middleware.

Abbiamo brevemente parlato di middleware quando abbiamo parlato del ciclo di vita di una richiesta HTTP in Laravel. È un meccanismo che permette di distinguere diversi gruppi di rotta e di agire diversamente (o aggiungere azioni) in base al middleware a cui appartiene la singola richiesta. Laravel permette di definire diversi tipi di middleware e ogni richiesta può appartenere a più middleware.

In particolare, per quanto riguarda l’ambito dell’autenticazione, Laravel mette a disposizione due middleware:

  • guest per le richieste/risposte che provengono/sono inviate a client non autenticati
  • auth per le richieste/risposte che provengono/sono inviate a client non autenticati

Questi middleware, in particolare, sono impostati come “route-specific” e possono, quindi, essere applicati a ogni rotta, in modo indipendente da altri eventuali middleware.

NOTA: per altri route-specific middleware disponibili, consultare il file app/Http/Kernel.php

Come possiamo, quindi, impedire che un utente già autenticato acceda alle pagine di registrazione? Dichiarando che le richieste collegate alla registrazione possono essere gestite solo se la richiesta stessa appartiene al middleware guest.

// routes/web.php
// ...
Route::get('/register', array(RegisterController::class, 'create'))
  ->name('register')
  ->middleware('guest');

Route::post('/register', array(RegisterController::class, 'store'))
  ->middleware('guest');

NOTA: abbiamo aggiunto un “name” alla rotta, in modo da poter, poi, usare tale nome nella view per ricostruire l’esatta URI senza doverla riscrivere.

Se non si specifica altrimenti il comportamento dell’applicazione, Laravel redirigerà alla pagina “home” definita in app/Providers/RouteServiceProvider.php le richieste di accesso alla pagina di registrazione che fanno parte del middleware auth. Questo comportamento è codificato nel file app/Http/Middleware/RedirectIfAuthenticated.php

A questo punto, potremmo voler modificare la view delle pagine per mostrare un diverso contenuto a seconda che si tratti di un visitatore o di un utente autenticato. Per fare ciò, possiamo di nuovo utilizzare l’helper auth o delle specifiche direttive Blade pensate per scopi simili.

{{-- nel file layout comune a tutte le pagine della nostra applicazione --}}
{{-- ... --}}

<a href="{{ url('/') }}">Home<a>
@auth
  <span>Welcome {{ auth()->user()->name }}</span>
@else
  <a href="{{ route('login') }}">Login</a>
  <a href="{{ route('register') }}">Register</a>
@endauth

{{-- ... --}}

L’helper auth ci permette di accedere a informazioni specifiche della sessione autenticata in corso, quindi, ad esempio, lo User attivo per ricavare le informazioni dalla relativa tabella.

Le direttive @auth e @guest operano come degli if, permettendo quindi di racchiudere al loro interno porzioni della view da renderizzare nel caso in cui la richiesta e il relativo rendering della view siano rispettivamente da un utente autenticato o da un visitatore.

Il controllo del middleware, l’helper auth e le direttive @auth e @guest potranno essere utilizzate in ogni rotta, controller e view della nostra applicazione per costruire contenuti personalizzati o per gestire comportamenti vari legati alla autenticazione.

Login e logout: avviare e terminare una sessione autenticata in Laravel

Per concludere le funzionalità (minime) legate all’autenticazione della nostra applicazione Laravel, mancano all’appello due flussi: quello di login e quello di logout.

Anche in questo caso, andremo ad operare con l’helper auth e andremo ad agire sui due middleware. Ovviamente, ci sono diversi modi in cui è possibile intervenire nello specifico, specie per quanto riguarda la definizione di rotte e controller che gestiscono l’esecuzione effettiva del cambio. In questo esempio, opteremo per un singolo controller che gestisce la “sessione autenticata”

$ php artisan make:controller SessionController
INFO  Controller [app/Http/Controllers/SessionController.php] created successfully.
// app/Http/Controllers/SessionController.php
class SessionController extends Controller
{
  public function destroy()
  {
    auth()->logout()
  }
}

// routes/web.php
// ...
Route::get('/logout', array(SessionController::class, 'destroy'))
  ->name('logout')
  ->middleware('auth');

{{-- nel file layout comune a tutte le pagine della nostra applicazione --}}
{{-- ... --}}

<a href="{{ url('/') }}">Home<a>
@auth
  <span>Welcome {{ auth()->user()->name }}</span>
  <a href="{{ route('logout') }}">Log Out</>
@else
  <a href="{{ route('login') }}">Log In</a>
  <a href="{{ route('register') }}">Register</a>
@endauth

{{-- ... --}}

In questo caso abbiamo implementato una soluzione che:

  • ha il suo “nucleo” nell’esecuzione di auth()->logout(): è la chiamata a questo metodo che esegue, nella pratica, il logout
  • abbiamo limitato l’esecuzione del metodo del controllo solo alle richieste che fanno parte del middleware auth (inutile far chiamare logout a chi è guest)
  • abbiamo usato la direttiva @auth per mostrare nella view il link solo a chi è autenticato

Per quanto riguarda, invece, il flusso di login, dovremo, ovviamente, fornire un form e interfacciarci con il model. Possiamo scegliere se creare un controller dedicato o unire il tutto in quello realizzato per il logout (concettualmente, avviamo e terminiamo la sessione).

// app/Http/Controllers/SessionController.php
class SessionController extends Controller
{
  public function create()
  {
    return view('session.create');
  }

  public function store(Request $request)
  {
    $attributes = $request->validate([
      'email' => ['required', 'email'],
      'password' => ['required'],
    ]);

    // tenta autenticazione con credenziali fornite
    if(auth()->attempt($attributes)) {
      // login riuscito,
      return redirect('/');
    }
   
    // gestire errore nel login
    return back()->withError(['login-error' => 'Wong credentials!']);
  }
}

// routes/web.php
// ...
Route::get('/login', array(SessionController::class, 'create'))
  ->name('login')
  ->middleware('guest');

Route::post('/register', array(SessionController::class, 'store'))
  ->middleware('guest');

Contattaci senza impegno per informazioni sul corso

Pagamento rateale

Valore della rata: A PARTIRE DA 115 €/mese.

Esempio di finanziamento 

Importo finanziato: € 2440 in 24 rate da € 115 – TAN fisso 9,55% TAEG 12,57% – importo totale del credito € 2841.

Il costo totale del credito comprende: interessi calcolati al TAN indicato, oneri fiscali (imposta di bollo sul contratto 16,00 euro*) addebitati sulla prima rata, costo mensile di gestione pratica € 3,90, spesa di istruttoria € 0,00, spesa per invio rendicontazione periodica cartacea € 0,98 (o spesa per invio rendicontazione periodica cartacea € 0,00), imposta di bollo su rendicontazione periodica € 0,00. Modalità di rimborso obbligatoria: addebito diretto su c/c. La scadenza delle rate è determinata dal giorno della liquidazione del contratto; la data di scadenza delle rate è prevista il giorno 15 del mese. L’importo di ciascuna rata comprende una quota di capitale crescente e interessi decrescente secondo un piano di ammortamento “alla francese”. Offerta valida dal 01/01/2024 al 31/12/2024.

Messaggio pubblicitario con finalità promozionale. Per le informazioni precontrattuali richiedere sul punto vendita il documento “Informazioni europee di base sul credito ai consumatori” (SECCI) e copia del testo contrattuale. Salvo approvazione di Sella Personal Credit S.p.A. Aulab S.r.l. opera quale intermediario del credito NON in esclusiva.

*In fase di richiesta del finanziamento verrà proposta la facoltà di selezionare, in alternativa all’imposta di bollo sul contratto di 16,00 euro, l’imposta sostitutiva, pari allo 0,25% dell’importo finanziato.

Pagamento rateale

Valore della rata: A PARTIRE DA 210 €/mese.

Esempio di finanziamento  

Importo finanziato: € 4500 in 24 rate da € 210,03 – TAN fisso 9,68% TAEG 11,97% – importo totale del credito € 5146,55.

Il costo totale del credito comprende: interessi calcolati al TAN indicato, oneri fiscali (imposta di bollo sul contratto 16,00 euro*) addebitati sulla prima rata, costo mensile di gestione pratica € 3,90, spesa di istruttoria € 0,00, spesa per invio rendicontazione periodica cartacea € 0,98 (o spesa per invio rendicontazione periodica cartacea € 0,00), imposta di bollo su rendicontazione periodica € 0,00. Modalità di rimborso obbligatoria: addebito diretto su c/c. La scadenza delle rate è determinata dal giorno della liquidazione del contratto; la data di scadenza delle rate è prevista il giorno 15 del mese. L’importo di ciascuna rata comprende una quota di capitale crescente e interessi decrescente secondo un piano di ammortamento “alla francese”. Offerta valida dal 01/01/2024 al 31/12/2024.

Messaggio pubblicitario con finalità promozionale. Per le informazioni precontrattuali richiedere sul punto vendita il documento “Informazioni europee di base sul credito ai consumatori” (SECCI) e copia del testo contrattuale. Salvo approvazione di Sella Personal Credit S.p.A. Aulab S.r.l. opera quale intermediario del credito NON in esclusiva.

* In fase di richiesta del finanziamento verrà proposta la facoltà di selezionare, in alternativa all’imposta di bollo sul contratto di 16,00 euro, l’imposta sostitutiva, pari allo 0,25% dell’importo finanziato.

Contattaci senza impegno per informazioni sul corso

Scopriamo insieme se i nostri corsi fanno per te. Compila il form e aspetta la chiamata di uno dei nostri consulenti.