Autenticazione JWT tra Lumen e client di frontend utilizzando la libreria tymon/jwt-auth

Recentemente per l’inizio di nuovi progetti personali e di lavoro, sono tornato a ragionare, come quasi sempre uso fare all’inizio dei nuovi progetti, delle tecnologie e gli strumenti utili sulle quali fondare le basi.
Sono sempre dell’idea che ogni progetto faccia storia a sè e necessita delle migliori tecnologie e linguaggi di programmazione utili al raggiungimento dello scopo.

Per diversi progetti, ho affrontato lo sviluppo del lato backend con il framework Laravel trovandomi bene con esso per diverse ragioni. Con esso è possibile avere una solida autenticazione fin da subito, e che è possibile ottenere anche con diversi approcci, anche contemporaneamente: Sessioni, JWT, Passport etc.

Si pensi ad esempio allo sviluppo di applicazioni web non particolarmente complesse per le quali non si ha grosse necessità di scalabilità e che pertanto per esse può essere sufficiente la più semplice delle autenticazioni basata sulle sessioni.
Anche per questa tipologia di applicazioni però, può nascere l’esigenza di ottenere un autenticazione differente. Si pensi per esempio alla necessità di dover sviluppare anche l’applicazione per smartphone. Sebbene sia comunque fattibile utilizzare le sessioni per l’autenticazione di una applicazione mobile, sarebbe comunque consigliabile partire con il piede giusto e configurare l’app mobile con una autenticazione con JWT più moderna e maggiormente scalabile.

La suddetta necessità mi è capitata nello sviluppo di un piccolo progetto web based, per il quale poi si è affacciata anche la necessità di avere app mobile. Per esso dunque decisi di affiancare l’autenticazione JWT alla autenticazione di laravel basata su sessione, senza stravolgere il comportamente della applicazione già scritta.

Risultato fu che con poche righe di codice e un minimo di comprensione del lavoro svolto, fu possibile configurare il backend di quell’applicazione per accettare da subito il nuovo frontend. L’app mobile.

Fu molto semplice, e per integrare egregiamente l’autenticazione JWT con Laravel ci sono diverse guide atte allo scopo.

Se si comprende bene programmazione e framework che si utilizzano, la seguente guida, sebbene sia orientata ad altro framework con impostazioni e logiche leggermente diverse, potrebbe essere facilmente adattabile anche ad un backend basato su laravel.

La seguente guida, come ho anticipato poco sopra, permetterà di far dialogare un qualsiasi frontend, con un backend basato su framework lumen. Al momento il mio codice gira sulla versione 5.8 del framework ma credo che sia perfettamente adattabile anche su molte altre versioni dello stesso, anche precedenti. Almeno fino alla 5.2!

Iniziamo subito col dire che per la guida verranno utilizzate i seguenti framework:

"laravel/lumen-framework": "5.8.*"

e le seguenti librerie:

"tymon/jwt-auth": "1.0.*"

Basta, per ciò a cui miriamo non serve altro.

"firebase/php-jwt": "^5.0"

La scelta dell’utilizzo di lumen dovrebbe essere piuttosto semplice da comprendere e condivisibile dai molti.
La scelta invece di utilizzare la libreria JWT di Tymon, va brevemente commentata.
Scelgo di utilizzare una libreria come questa, per l’immediatezza e la completezza che riesce ad offrire con la sua installazione. Una libreria che è già completa di tutto, pronta all’uso e pensata per essere pronta alla produzione. Non ho bisogno di altro relativamente il suo compito, pertanto è facile capire che con essa è possibile mirare dritti allo scopo.
Avessimo dovuto programmare per studio, o per implementare qualcosa di differente dall’uso comune, avremmo potuto pensare anche di includere solo una libreria semplice. Questa ad esempio:

Con questa è possibile sempre creare un token, in maniera semplice ed immediata, ma controlli e metodi di verifiche vanno scritte da zero. E questa è completamente un altra storia.

Prima cosa prima: Installazione del framework e della libreria.
Due semplici comandi:

composer create-project --prefer-dist laravel/lumen nomecartella
composer require tymon/jwt-auth
Abbiamo così installato il nostro ambiente di lavoro, boilerplate, che andrà successivamente configurato.
Concludiamo con il terminale, con questo comando:
php artisan jwt:secret

Apriamo il file app/Providers/AppServiceProvider.php e nel metodo register, inseriamo questo codice: per la registrazione della classe:

$this->app->register(\Tymon\JWTAuth\Providers\LumenServiceProvider::class);

Passiamo al file config/auth.php
Il file dovrebbe rimanere tale, bisogna al più assicurarsi che il guards, abbia come driver jwt

'guards' => [
   'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
        'hash' => false,
   ]
]

Spostiamoci sul file app/Providers/AuthServiceProvider.php
e modifichiamo il metodo boot().

Cancelliamone il contenuto e lo sostituiamo con quanto segue:

$this->app['auth']->viaRequest('api', function ($request){
    return \App\User::where('email', $request->input('email'))->first();
});

Passiamo ora alla configurazione e scrittura del Modello e del controller.

Sul file app/User.php

modifichiamone l’implementazione, in questo modo:

class User extends Model implements JWTSubject, AuthenticatableContract, AuthorizableContract

In sostanza, oltre quanto già scritto di default, andiamo ad aggiungere anche quanto messo in grassetto: JWTSubject

Aggiungiamo inoltre due metodi necessari:

public function getJWTIdentifier(){
    return $this->getKey();
}

public function getJWTCustomClaims(){
    return [];
}

Infine il controller: Questo file probabilmente andrà proprio creato, pertanto provvediamo chimandolo AuthController.php nella cartella app/Http/Controllers

In esso incolliamo questo codice:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Tymon\JWTAuth\JWTAuth;

class AuthController extends Controller
{
    /**
     * @var \Tymon\JWTAuth\JWTAuth
     */
    protected $jwt;

    public function __construct(JWTAuth $jwt)
    {
        $this->jwt = $jwt;
    }

    public function postLogin(Request $request)
    {
        $this->validate($request, [
            'email'    => 'required|email|max:255',
            'password' => 'required',
        ]);

        try {

            if (! $token = $this->jwt->attempt($request->only('email', 'password'))) {
                return response()->json(['user_not_found'], 404);
            }

        } catch (\Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {

            return response()->json(['token_expired'], 500);

        } catch (\Tymon\JWTAuth\Exceptions\TokenInvalidException $e) {

            return response()->json(['token_invalid'], 500);

        } catch (\Tymon\JWTAuth\Exceptions\JWTException $e) {

            return response()->json(['token_absent' => $e->getMessage()], 500);

        }

        return response()->json(compact('token'));
    }
}

La nostra autenticazione è pronta: non ci resta che creare la rotta e testarla.
Nel file routes/web.php aggiungiamo la rotta necessaria:

$router->post('/auth/login', 'AuthController@postLogin');

E la interroghiamo con curl o magari postman passando due semplici dati, email e password.

Questo è quanto! Avremo così un sistema pronto all’uso e che potrebbe essere la base iniziale di tutti i nostri progetti, al netto delle modifiche e customizzazioni che di volta in volta dovremo andare a fare. Non sarebbe in effetti una cattiv idea, tenerlo come base dei nostri progetti e di volta in volta clonarlo per ripartire da questa base.

Voi invece? come implementate l’autenticazione sui vostri sistemi? Lasciate i vostri dubbi le perplessità ed i suggerimenti nei commenti.

Bibliografia utile per lo studio di questo lavoro:

  • https://iwader.co.uk/post/tymon-jwt-auth-with-lumen-5-2
  • https://medium.com/@keithchasen/lumen-app-authorization-with-jwt-and-doctrine-3427cd3cb41
  • https://blog.pusher.com/laravel-jwt/
  • https://tutsforweb.com/restful-api-in-laravel-56-using-jwt-authentication/

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Su questo sito utilizziamo cookie tecnici e, previo tuo consenso, cookie di profilazione, nostri e di terze parti, per proporti pubblicità in linea con le tue preferenze.
Cliccando il pulsante accetto presti il consenso al loro uso.