Tempo di lettura: 11 minuti
In questo tutorial vi spiego come realizzare un’autenticazione con React ed il Jwt di laravel 9.
Per proteggere l’API di autenticazione dell’utente in Laravel useremo la libreria di terze parti tymondesigns/jwt-auth.
Nella seconda parte del tutorial realizzeremo la parte front end con React dove andremo ad autenticarci utilizzando l’API realizzata precedentemente.
Che cosa è il json web token
Il json web token (jwt) è uno standard aperto (rfc 7519) e rappresenta un metodo compatto e autonomo per la trasmissione sicura di informazioni tra le parti come oggetto JSON.
La firma digitale rende affidabile e verificata la trasmissione degli stessi tramite jwt. Questi si basano su un algoritmo segreto HMAC o su una coppia di chiavi pubblica/privata tramite RSA o ECDSA.
Autenticazione con React ed il jwt di laravel 9: requisiti
Prima di continuare mi aspetto che conosciate di già la Libreria React nella sua ultima versione, difatti faremo uso degli hooks e Laravel , anche in questo caso faremo uso dell’ultima versione , cioè la 9.
A dire il vero avevo già scritto un’articolo in merito anche se un pò diverso in quanto in questo caso non utilizzeremo lo scaffolding di React in Laravel ma gli stessi saranno separati risiedendo in due server diversi.
Installa laravel
Come recita la documentazione di Laravel aprite un terminale , fatelo puntare su una vostra directory a piacere e digitate :
composer create-project laravel/laravel backend --prefer-dist
bene ora attendete il tempo necessario affinchè venga creato il progetto.
Una volta terminato all’interno della vostra directory vi troverete una cartella di nome backend, ok ora dovete realizzare il database.
Realizza e connettiti al database
Per poter realizzare e connetterci ad un db utilizzerò il web server locale Laragon , voi utilizzatene pure uno a piacere. Se state utilizzando Laragon apritelo e fate click su terminale, quindi digitate:
mysql -u root -p
la -u sta per user che nel mio caso in locale è root e la -p sta per password. Fate invio, in password: fate semplicemente invio in quanto in locale non la abbiamo configurata.
se tutto è ok potete digitare:
Create database OMDB_DB;
Avete appena realizzato il vostro database, potete uscire dal terminale.
Aprite il vostro progetto con il vostro Ide a piacere quindi aprite il file .env e configurate LA PARTE RELATIVA AL DATABASE come di seguito:
... DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=OMDB_DB DB_USERNAME=root DB_PASSWORD= ...
Aggiungi la tabella utente al database
Una volta creato il database possiamo fare la nostra prima migration aggiungendo la tabella User allo stesso, aprite il terminale e digitate:
php artisan migrate
Se aprite il database noterete la tabella appena creata:
Installa e configura il pacchetto di autenticazione JWT
tymondesigns/jwt-auth è un pacchetto JWT di terze parti e consente l’autenticazione dell’utente utilizzando il JWT in laravel e lumen in modo sicuro.
Per scaricarlo da terminale digitate:
composer require tymon/jwt-auth
Una volta scaricato aprite il file config/app.php ed includete il provider di servizi laravel all’interno di provider nell’array:
'providers' => [ .... .... Tymon\JWTAuth\Providers\LaravelServiceProvider::class, ], 'aliases' => [ .... 'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class, 'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class, .... ],
quindi pubblichiamo la configurazione del package digitando il seguente comando da terminale:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
ora osiamo generare una secret key per gestire la crittografia del token:
php artisan jwt:secret
se aprite il file .env potete notare una nuova riga che certifica la corretta generazione della key:
... JWT_SECRET=wsdrFDtNU32B5qsEbxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
Configura lo User Model
Aprite il model User in app/models/User.php e definite due nuovi metodi per poter utilizzare il package di Tymon, come di seguito:
<?php namespace App\Models; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { use HasApiTokens, HasFactory, Notifiable; /** * The attributes that are mass assignable. * * @var array<int, string> */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for serialization. * * @var array<int, string> */ protected $hidden = [ 'password', 'remember_token', ]; /** * The attributes that should be cast. * * @var array<string, string> */ protected $casts = [ 'email_verified_at' => 'datetime', ]; public function getJWTIdentifier() { return $this->getKey(); } /** * Return a key value array, containing any custom claims to be added to the JWT. * * @return array */ public function getJWTCustomClaims() { return []; } }
dove con getJWTIdentifier si ottiene l’identificatore che verrà poi archiviato nella rivendicazione dell’oggetto del jwt.
getJWTCustomClaims restituisce una matrice di valori chiave , contenente attestazioni personalizzate da aggiungere al jwt.
Configura l’autenticazione protetta
Aprite il file config/auth.php ed impostiamo la guardia predefinita su api e, di conseguenza, a questi viene detto di utilizzare il driver jwt:
... return [ 'defaults' => [ 'guard' => 'api', 'passwords' => 'users', ], 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'jwt', 'provider' => 'users', 'hash' => false, ], ], ...
Realizza il controller per l’autenticazione
Nel controller relativo all’autenticazione definiremo la logica principale per il processo di autenticazione sicura. Da terminale digitate:
php artisan make:controller AuthController
inserisci il seguente codice all’interno del file app/Http/Controllers/AuthController.php:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use App\Models\User; use Validator; class AuthController extends Controller { /** * Create a new AuthController instance. * * @return void */ public function __construct() { $this->middleware('auth:api', ['except' => ['login', 'register']]); } /** * Get a JWT via given credentials. * * @return \Illuminate\Http\JsonResponse */ public function login(Request $request){ $validator = Validator::make($request->all(), [ 'email' => 'required|email', 'password' => 'required|string|min:6', ]); if ($validator->fails()) { return response()->json($validator->errors(), 422); } if (! $token = auth()->attempt($validator->validated())) { return response()->json(['error' => 'Unauthorized'], 401); } return $this->createNewToken($token); } /** * Register a User. * * @return \Illuminate\Http\JsonResponse */ public function register(Request $request) { $validator = Validator::make($request->all(), [ 'name' => 'required|string|between:2,100', 'email' => 'required|string|email|max:100|unique:users', 'password' => 'required|string|confirmed|min:6', ]); if($validator->fails()){ return response()->json($validator->errors()->toJson(), 400); } $user = User::create(array_merge( $validator->validated(), ['password' => bcrypt($request->password)] )); return response()->json([ 'message' => 'User successfully registered', 'user' => $user ], 201); } /** * Log the user out (Invalidate the token). * * @return \Illuminate\Http\JsonResponse */ public function logout() { auth()->logout(); return response()->json(['message' => 'User successfully signed out']); } /** * Refresh a token. * * @return \Illuminate\Http\JsonResponse */ public function refresh() { return $this->createNewToken(auth()->refresh()); } /** * Get the authenticated User. * * @return \Illuminate\Http\JsonResponse */ public function userProfile() { return response()->json(auth()->user()); } /** * Get the token array structure. * * @param string $token * * @return \Illuminate\Http\JsonResponse */ protected function createNewToken($token){ return response()->json([ 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => auth()->factory()->getTTL() * 60, 'user' => auth()->user() ]); } }
Il middleware auth:api viene utilizzato all’interno del costruttore della classe; non è possibile accedere ai metodi all’interno del controller di autenticazione senza disporre di un token valido. Inoltre possiamo passare il nome delle funzioni all’interno del middleware che vogliamo siano escluse dall’obbligo del token.
Metodo login
Il metodo login consente l’autenticazione dell’utente mediante password ed email, in risposta genera un token di autorizzazione a patto che trovi l’utente all’interno del db. Nel caso contrario restituisce un errore.
Metodo register
Con il metodo register inseriamo un nuovo utente nel db tramite dei campi con relativa validazione.
Metodo logout
Con il metodo logout cancelliamo il token dell’utente loggato, molto semplicemente.
Metodo Refresh
Questo crea un nuovo Token.
Metodo userProfile
Esegue il rendering dei dati dell’utente connesso che abbia un token valido.
Metodo createNewToken
Questa funzione crea un nuovo token di autenticazione dopo la sua scadenza o eliminazione.
Aggiungi le routes per l’autenticazione
Trattandosi di una API REST i percorsi ,o routes, dell’applicazione relativi all’autenticazione vanno inseriti all’interno del file routes/api.php e non in web.php. Quindi aprite il primo e modificate come di seguito:
<?php use App\Http\Controllers\AuthController; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; /* |-------------------------------------------------------------------------- | API Routes |-------------------------------------------------------------------------- | | Here is where you can register API routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | is assigned the "api" middleware group. Enjoy building your API! | */ Route::middleware('auth:sanctum')->get('/user', function (Request $request) { return $request->user(); }); Route::group([ 'middleware' => 'api', 'prefix' => 'auth' ], function ($router) { Route::post('/login', [AuthController::class, 'login']); Route::post('/register', [AuthController::class, 'register']); Route::post('/logout', [AuthController::class, 'logout']); Route::post('/refresh', [AuthController::class, 'refresh']); Route::get('/user-profile', [AuthController::class, 'userProfile']); });
Testare l’API di autenticazione con POSTMAN
Prima di passare alla realizzazione del front-end è sempre buona norma testare l’API REST. A tal proposito utilizzeremo postman, per cui vi consiglio di scaricarlo ed installarlo se non lo avete.
Registrazione
Aprite postman e nella barra degli indirizzi digitate l’indirizzo relativo al metodo register definito nel file routes/api.php, non vi scordate prima di servire l’applicazione:
ok selezionate il metodo POST per la richiesta HTTP, quindi selezionate body, form-data e sotto inserite i nomi dei campi definiti nella request con i relativi valori. Una volta fatto fate click su SEND.
Se tutto ok verrà restituito un oggetto di tipo json con le info relative all’utente registrato.
Login
Una volta aggiunto un utente al database possiamo testare anche la fase di autenticazione e rendersi conto se in effetti viene creato un token. Sempre in postman aggiungete una nuova scheda cliccando su +:
nella barra degli indirizzi questa volta digitate http://127.0.0.1:8000/api/auth/login, selezionate ancora una volta il metodo POST
se tutto è andato a buon fine vi verrà restituito una serie di informazioni sempre in json compreso il nostro token.
UserProfile
In postman aggiungete una nuova scheda ed inserite l’indirizzo http://127.0.0.1:8000/api/auth/user-profile, questa volta selezionate il metodo HTTP GET. Selezionate Authorization , in TYPE selezionate Bearer Token, nella finestra a destra incollate il token restituito dopo aver fatto il login:
in basso ,se avete incollato il token correttamente, vi verrà restituito le info relativamente al titolare del token.
Metodo refresh
Per aggiornare un token è necessario averne uno valido. Aggiungete una nuova scheda in postman ed inserite l’indirizzo http://127.0.0.1:8000/api/auth/refresh, selezionate questa volta il metodo POST, poi il resto rimane invariato rispetto al metodo userProfile:
se prestate attenzione ogni volta che fate click su SEND il token si aggiorna.
Metodo logout
Aggiungete una nuova scheda in postman , digitate l’indirizzo http://127.0.0.1:8000/api/auth/logout, metodo POST, poi tutto rimane invariato rispetto al refresh purchè inseriate l’ultimo token aggiornato nell’apposito campo:
fate click su SEND ed il token verrà cancellato.
Conclusione
Nella prima parte del tutorial abbiamo realizzato una REST API con Laravel9 relativa ad un’autenticazione sicura mediante JWT. Prima di procedere alla realizzazione del front end con React (cosa che faremo nella seconda parte del tutorial) abbiamo giustamente testato il tutto con Postman.
Puoi scaricare e/o visionare il codice su GitHub.