Tempo di lettura: 13 minuti
In questo tutorial realizzeremo un sistema di autenticazione completo con Laravel e Jwt (json web token), alla fine sarete in grado di realizzare una API REST sicura.
Laravel rende tale operazione relativamente semplice e veloce grazie ad una struttura già predisposta a realizzare tale funzionalità, e lo vedremo di seguito.
Laravel e JWT: Cosa è Laravel
Ciò si potrebbe definire in poche parole, come una boccata d’aria fresca.
Lasciatemi partire dalla mia esperienza personale. Negli ultimi dieci anni, sia per lavoro che per hobby, ho lavorato molto con PHP ed i suoi framework. Ne ho visti alcuni, rimanendo legato essenzialmente a Simphony. Quando ho scoperto Laravel, però, le cose sono cambiate del tutto.
Questo è un framework PHP, ovviamente orientato alla programmazione ad oggetti ed al pattern architetturale MVC (che se non conoscete consiglio caldamente di studiarvi) e all’eliminazione di uno dei nostri peggiori nemici, lo spaghetti code. Presenta, inoltre, un comodo sistema di bundles per “pacchettizzare” i nostri software (parliamo quindi di HMVC), in modo tale da creare applicazioni sempre più sofisticate e al tempo stesso facilmente manutenibili.
La sua storia comincia nel 2011, quando Taylor Otwell decide di “rendere lo sviluppo web più facile e divertente, perché è quello che amo fare”. Da allora di strada ne è stata fatta, nonostante siano passati solo poco meno di due anni.
Attualmente, infatti, il progetto è arrivato alla versione 7 e ha sicuramente tante buone carte da giocare. Anzi, ottime carte come un sistema di authentication facile da usare, un ORM già pronto (Eloquent) oppure un command line tool integrato (Artisan).
Laravel e JWT: Cosa è il json web token
Il JSON Web Token (JWT) è uno standard open (RFC 7519) che definisce uno schema in formato JSON per lo scambio di informazioni tra vari servizi.
Il token generato può essere firmato (con una chiave segreta che solo chi genera il token conosce) tramite l’algoritmo di HMAC, oppure utilizzando una coppia di chiavi (pubblica / privata) utilizzando gli standard RSA o ECDSA.
I JWT sono molto utilizzati per autenticare le richieste nei Web Services e nei meccanismi di autenticazione OAuth 2.0 dove il client invia una richiesta di autenticazione al server, il server genera un token firmato e lo restituisce al client che, da quel momento in poi, lo utilizzerà per autenticare le successive richieste.
Se volete saperne di più cliccate qui.
Installare laravel
Prima di installare Laravel dobbiamo installare Composer, ovvero il tool che ci permette di installare e aggiornare le librerie esterne in modo molto semplice. Scegliete la versione che fa al caso del vostro sistema operativo e procedete con l’installazione. Se siete sotto Windows scaricatevi il file .exe come in figura:
Ora ,come recita la documentazione ufficiale del nostro Framewok, avete due possibilità per installarlo. La prima procedura, più veloce, consiste nell’installare prima laravel/installer globalmente in modo tale da averlo disponibile sempre:
composer global require laravel/installer
quindi poi semplicemente :
laravel new namesite
sappiate però che questo richiede l’installazione nella vostra macchina di una versione di PhP non inferiore alla 7.3 altrimenti genera errore.
Per quanto riguarda la seconda procedura molto semplicemente digitate :
composer create-project --prefer-dist laravel/laravel namesite
Laravel e jwt: creiamo il progetto
Createvi una directoy nel vostro pc , aprite il terminale dirigetevi all’interno di essa e digitate:
composer create-project laravel/laravel laravel-jwt-auth --prefer-dist
attendete qualche istante, il tempo che venga scaricato il progetto Laravel.
Una volta terminato dirigetevi all’interno di questa, sempre da terminale, mediante:
cd laravel-jwt-auth
ora avviate il server:
php artisan serve
quindi aprite il browser all’indirizzo http://127.0.0.1:8000 , se tutto è andato bene vi si aprirà la home del vostro progetto.
Laravel e jwt: connessione con il db
Per poter lavorare con Laravel, framework php, è palese che nella vostra macchina sia installato un server locale come Xampp, Mamp o Wamp.
Io utilizzo Xampp, per cui lo avvio, apro la console in esso e vado a realizzare il db mediante i comandi:
mysql -u root -p
quando vi chiede la password inseritela o, se non la avete, date semplicemente invio:
a questo punto siamo pronti per creare il db, digitate:
CREATE DATABASE laravel_jwt;
verificate che in effetti sia stato creato:
SHOW databases;
se il db, appena creato risulta in lista è ok.
Configura il file .env
Aprite il progetto Laravel, quindi il file .env, questo è un file di configurazione del framework. Dunque configurate la connessione al db creato precedentemente:
... DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_jwt DB_USERNAME=root DB_PASSWORD= ...
da terminale ora digitate:
php artisan migrate
ricordatevi di impartire i comandi sempre dall’interno della root principale del progetto.
Se vi da errore ricontrollate la configurazione della connessione al db, altrimenti aprite phpmyadmin e dovreste trovare il db creato con alcune tabelle come in figura:
Installa il package di autenticazione Jwt
Tymondesigns / jwt-auth è un pacchetto JWT di terze parti e consente l’autenticazione utente utilizzando il JSON Web Token in Laravel & Lumen in modo sicuro.
Da terminale spostati all’interno della root principale ed esegui:
composer require tymon/jwt-auth
Nota: se dovesse restituirvi un errore tipo:
Composer require runs out of memory. PHP Fatal error: Allowed memory size of 1610612736 bytes exhausted
allora prima di installare tymon/jwt-auth digitate ,sempre da terminale:
set COMPOSER_MEMORY_LIMIT=-1n pratica aumentate memoria da composer.
finita l’installazione aprite il file config/app.php ed aggiungetelo nel provider:
'providers' => [ .... /* * Package Service Providers... */ 'Tymon\JWTAuth\Providers\LaravelServiceProvider', /* * Application Service Providers... */ ], 'aliases' => [ .... 'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth', 'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory' ],
ora con la seguente istruzione pubblichiamo il pacchetto:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
Per gestire la crittografia del token, genera una chiave segreta eseguendo il seguente comando:
php artisan jwt:secret
Abbiamo generato con successo la chiave segreta JWT ,la puoi controllarenel file .env
:
... JWT_SECRET=9fzOtDk9TYEEfGnpC5klZ5qBejbP5GpEeXnltgCPat7r34G4gGnbJgisqE41TNw9 ...
Modifica il Model User
Nel framework MVC ,la lettera “M” sta per model. I model, o modelli, sono mezzi per gestire la logica dell’applicazione basate su tale architettura.
In Laravel il Model non è nient’altro che una classe la quale rappresenta la struttura logica e la relazione delle tabelle.
Ogni tabella ha un Model e ci consente di interagire con la stessa. Questi ti danno la possibilità ,quindi, di recuperare,inserire ed aggiornare le informazioni nella tabella relativa.
I model si trovano sotto la directory App/Models.
Laravel ha già un model User predefinito sotto App/Models/User.php, noi lo utilizzeremo per il processo di autenticazione, apritelo ed implementiamo il package jwt-auth :
<?php namespace App; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { use Notifiable; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; public function getJWTIdentifier() { return $this->getKey(); } public function getJWTCustomClaims() { return []; } }
-
getJWTIdentifier()
: Riceve l’identificatore che verrà archiviato nella rivendicazione del soggetto del JWT. -
getJWTCustomClaims()
: Restituisce una matrice di valori chiave, contenente eventuali attestazioni personalizzate da aggiungere al JWT.
Aggiungi le routes per l’autenticazione
Prima di realizzare le routes per l’autenticazione creeremo un Middleware che abbia il compito di proteggere le stesse. Questo non è nient’altro che un meccanismo il quale serve a filtrare programmaticamente le richieste HTTP ricevute dalla vostra applicazione.
Ad esempio Laravel include un Middleware di default che verifica se l’utente è autenticato. Se non lo è, il Middleware reindirizzerà il visitatore alla schermata Login. Se l’utente invece lo è, alla richiesta, gli sarà permesso di continuare l’esecuzione come per intenzione.
Da terminale eseguite:
php artisan make:middleware JwtMiddleware
Una volta creato lo trovate sotto app/Http/Middleware/JwtMiddleware , apritelo e modificate come di seguito:
<?php namespace App\Http\Middleware; use Closure; use JWTAuth; use Exception; use Tymon\JWTAuth\Http\Middleware\BaseMiddleware; class JwtMiddleware extends BaseMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { try { $user = JWTAuth::parseToken()->authenticate(); } catch (Exception $e) { if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenInvalidException){ return response()->json(['status' => 'Token is Invalid']); }else if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException){ return response()->json(['status' => 'Token is Expired']); }else{ return response()->json(['status' => 'Authorization Token not found']); } } return $next($request); } }
Tale middleware estende Tymon\JWTAuth\Http\Middleware\BaseMiddleware
, con lo stesso possiamo rilevare gli errori dei token e restituire tali codici specifici ai nostri utenti.
Successivamente dovete registrarlo, aprite il file app/http/Kernel.php e digitate:
[...] protected $routeMiddleware = [ [...] 'jwt.verify' => \App\Http\Middleware\JwtMiddleware::class, ]; [...]
bene siamo pronti per creare le rotte, aprite il file routes/api.php e modificate:
<?php use App\Http\Controllers\DataController; use App\Http\Controllers\UserController; 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::post('register', [UserController::class,'register'])->name('register'); Route::post('login', [UserController::class,'authenticate'])->name ('login'); Route::get('open', [DataController::class,'open'])->name('open'); Route::group(['middleware' => ['jwt.verify']], function() { Route::get('user', [UserController::class,'getAuthenticatedUser'])->name('user'); Route::get('closed', [DataController::class,'closed'])->name('closed'); });
Ho definito tutti i percorsi necessari per testare JWT. Ho tenuto fuori dal Middleware group tutte quelle rotte che non necessitano di protezione.
Crea il controller per l’autenticazione
Nonostante Laravel permetta di definire alcuni comportamenti direttamente nel file routes.php
, questo approccio non è scalabile. La soluzione perfetta per gestire i vari entry point delle nostre applicazioni è invece l’utilizzo dei controller.
Laravel ha previsto per questa tipologia di componente una cartella dedicata: app/Http/Controllers
e una classe da estendere Illuminate\Routing\Controller
.
Questo è una semplice classe che presenta diversi metodi pubblici. Ciascuno di questi ultimi viene associato ad una URL e ad un metodo HTTP. Per associare una URL ad un determinato controller si usa la sintassi NomeController@nomeMetodo
.
Per il nostro esempio creeremo due controller: UserController
e DataController
.
La UserController
conterrà la logica di autenticazione, mentre il DataController
restituirà dati di esempio.
Crea i controller:
$ php artisan make:controller UserController $ php artisan make:controller DataController
una volta creati aprite UserController seguendo il percorso app / Http / Controllers / UserController.php :
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class UserController extends Controller { // }
ecco come si presenta, come si può notare è una classe php, modificate come di seguito:
<?php namespace App\Http\Controllers; use App\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Validator; use JWTAuth; use Tymon\JWTAuth\Exceptions\JWTException; class UserController extends Controller { public function authenticate(Request $request) { $credentials = $request->only('email', 'password'); try { if (! $token = JWTAuth::attempt($credentials)) { return response()->json(['error' => 'invalid_credentials'], 400); } } catch (JWTException $e) { return response()->json(['error' => 'could_not_create_token'], 500); } return response()->json(compact('token')); } public function register(Request $request) { $validator = Validator::make($request->all(), [ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:6|confirmed', ]); if($validator->fails()){ return response()->json($validator->errors()->toJson(), 400); } $user = User::create([ 'name' => $request->get('name'), 'email' => $request->get('email'), 'password' => Hash::make($request->get('password')), ]); $token = JWTAuth::fromUser($user); return response()->json(compact('user','token'),201); } public function getAuthenticatedUser() { try { if (! $user = JWTAuth::parseToken()->authenticate()) { return response()->json(['user_not_found'], 404); } } catch (Tymon\JWTAuth\Exceptions\TokenExpiredException $e) { return response()->json(['token_expired'], $e->getStatusCode()); } catch (Tymon\JWTAuth\Exceptions\TokenInvalidException $e) { return response()->json(['token_invalid'], $e->getStatusCode()); } catch (Tymon\JWTAuth\Exceptions\JWTException $e) { return response()->json(['token_absent'], $e->getStatusCode()); } return response()->json(compact('user')); } }
Metodo Authenticate
Questo tenta di accedere ad un utente e genera un token di autorizzazione se lo stesso viene trovato nel database. Genera un errore se l’utente non viene trovato o se si è verificata un’eccezione durante il tentativo di trovarlo.
Metodo register
Il metodo register convalida un input dell’utente e lo crea se le credenziali dell’utente vengono convalidate. L’utente viene quindi passato a JWTAuth
per generare un token di accesso per l’utente creato. In questo modo, l’utente non avrebbe bisogno di accedere per ottenerlo.
Metodo getAuthenticatedUser
Questo restituisce l’oggetto utente in base al token di autorizzazione che viene passato.
Avvia il server con il seguente comando:
php artisan serve
Prova l’API di autenticazione Laravel e jwt con Postman
Postman è un tool utilissimo che consente di provare le nostre API in maniera molto più snella e semplice, evitando di realizzare driver/stub per testare i nostri servizi.
Ti consiglio di scaricarlo ed installarlo, dunque aprilo ed inserisci:
Registrazione
Endpoint: 127.0.0.1:8000/api/register
Metodo: POST
Payload:
name
: Test Man
email
: test@email.com
password
: secret
password_confirmation
: secret
Login Utente
Endpoint: 127.0.0.1:8000/api/login
Metodo: POST
Payload:
email
: test@email.com
password
: secret
Accesso a rotta non protetta
Endpoint: 127.0.0.1:8000/api/open
metodo:GET
Accesso ad End Point protetto
Endpoint: 127.0.0.1:8000/api/closed
Metodo: GET
Payload:
Authorization
: Bearer insert_user_token_here
Prova ad accedere ai dati protetti dal middleware utilizzando il token di autorizzazione.
Ottieni i dati utente autenticati
Endpoint: 127.0.0.1:8000/api/user
Metodo: GET
Payload:
Authorization
: Bearer insert_user_token_here
Utilizza un token non valido per accedere ai dati di un utente
Endpoint: 127.0.0.1:8000/api/user
Metodo: GET
Payload:
Authorization
: token fake
Accesso senza Token ad una rotta protetta
Endpoint: 127.0.0.1:8000/api/closed
metodo:GET
Conclusione
In questa guida, abbiamo esaminato il JWT e come utilizzarlo nelle applicazioni Laravel, impostato un controller per l’autenticazione e la registrazione dell’utente.
Avete anche definito un metodo per ottenere l’utente autenticato utilizzando il token generato ed, infine, visto come viene utilizzato per proteggere le nostre API e testato i dati di output utilizzando Postman.
Puoi utilizzare il JWT per proteggere i tuoi endpoint API a cui accederanno diversi utenti. Il JWT è un ottimo sistema per autenticare gli utenti.
Il codice sorgente dell’applicazione in questo articolo è disponibile su GitHub .