• oauth
  • jwt
  • api
  • sicurezza
  • autenticazione
  • autorizzazione
  • machine-to-machine

Proteggi le risorse API per la comunicazione da macchina a macchina

Scopri come sfruttare OAuth 2.0 e JWT per proteggere le risorse API per la comunicazione da macchina a macchina.

Gao
Gao
Founder

Quando costruisci un progetto che coinvolge più servizi, la sicurezza delle risorse API è una preoccupazione critica. In questo articolo, ti mostrerò come sfruttare OAuth 2.0 e JWT per proteggere la comunicazione tra servizi (da macchina a macchina) e come applicare il controllo degli accessi basato sui ruoli (RBAC) per seguire il principio del privilegio minimo.

Iniziamo

Per seguire insieme, presumo che tu abbia i seguenti prerequisiti:

  • Un account Logto Cloud, o un'istanza Logto self-hosted
  • Almeno due servizi che devono comunicare tra loro

Per scopi dimostrativi, supponiamo di avere i seguenti servizi:

  • Un servizio di carrello degli acquisti che fornisce API per gestire i carrelli degli acquisti
    • Endpoint: https://cart.example.com/api
  • Un servizio di pagamento che fornisce API per elaborare i pagamenti
    • Endpoint: https://payment.example.com/api

Flusso di autenticazione

Ora, il nostro servizio di carrello deve chiamare il servizio di pagamento per elaborare i pagamenti. Il flusso di autenticazione è il seguente:

Alcuni concetti chiave nel diagramma sopra:

  • JWT (RFC 7519): JSON Web Token. Vedi il nostro articolo precedente per un'introduzione a JWT.
  • JWK (RFC 7517): JSON Web Key, utilizzato per verificare la firma di un JWT. Un set JWK è un insieme di JWK.
  • "client_credentials" grant (RFC 6749): Un tipo di concessione in OAuth 2.0. Utilizza le credenziali del client per ottenere un token di accesso. Mostreremo i dettagli nelle sezioni successive.

Ogni partecipante nel diagramma sopra ha un ruolo nel flusso di autenticazione:

  • Servizio Carrello: Il client che deve chiamare il servizio di pagamento. Anche se è un servizio, è comunque un client nel contesto di OAuth 2.0 e chiamiamo questi client "applicazioni da macchina a macchina" in Logto.
  • Logto: Il server di autorizzazione OAuth 2.0 che emette i token di accesso.
  • Servizio di Pagamento: La risorsa API che fornisce API per elaborare i pagamenti.

Passiamo attraverso il flusso di autenticazione passo dopo passo.

Configurazione iniziale

Per eseguire il flusso di autenticazione, dobbiamo creare un'applicazione da macchina a macchina (servizio carrello) e una risorsa API (servizio di pagamento) in Logto.

Creazione di una risorsa API

Poiché il nostro servizio carrello deve essere a conoscenza dell'API del servizio di pagamento durante l'autenticazione, dobbiamo prima creare una risorsa API. Vai alla Console di Logto, fai clic su Risorse API nella barra laterale a sinistra e fai clic su Crea risorsa API. Nella finestra di dialogo aperta, offriamo alcuni tutorial per aiutarti a iniziare. Puoi anche fare clic su Continua senza tutorial per saltarlo.

Inserisci il nome dell'API e l'identificatore, ad esempio Servizio di Pagamento e https://payment.example.com/api, quindi fai clic su Crea risorsa API.

Dopo aver creato la risorsa API, verrai reindirizzato alla pagina dei dettagli. Possiamo lasciarlo com'è per ora.

Creazione di un'app da macchina a macchina

Fai clic su Applicazioni nella barra laterale a sinistra e fai clic su Crea applicazione. Nella finestra di dialogo aperta, trova la scheda Da macchina a macchina, quindi clicca su Inizia a costruire.

Inserisci il nome dell'applicazione, ad esempio Servizio Carrello, e clicca su Crea applicazione. Verrà mostrata una guida interattiva per aiutarti a configurare l'applicazione. Puoi seguire la guida per capire l'uso di base o cliccare su Termina e fatto per saltarla.

Richiedi il token di accesso

Poiché si presume che le applicazioni da macchina a macchina siano sicure (ad esempio, sono distribuite in una rete privata), possiamo usare il "client_credentials" grant di OAuth 2.0 per ottenere un token di accesso. Utilizza autenticazione di base per autenticare il client:

  • L'URL della richiesta è l'endpoint del token della tua istanza di Logto. Puoi trovarlo e copiarlo nella scheda Impostazioni avanzate della pagina dei dettagli dell'app da macchina a macchina.
  • Il metodo di richiesta è POST.
  • L'header Content-Type della richiesta è application/x-www-form-urlencoded.
  • Per l'header Authorization, il valore è Basic <base64(app_id:app_secret)>, dove app_id e app_secret sono l'ID e il segreto dell'app della tua app da macchina a macchina. Puoi trovarli nella pagina dei dettagli dell'applicazione.
  • Il corpo della richiesta deve specificare il tipo di concessione e l'identificatore dell'API. Ad esempio, grant_type=client_credentials&resource=https://payment.example.com/api.
    • grant_type=client_credentials: Il valore costante per il "client_credentials" grant.
    • resource=https://payment.example.com/api: L'identificatore dell'API della risorsa API a cui il client vuole accedere.
    • Se l'applicazione deve essere autorizzata con scope (permessi), puoi anche specificare gli scope nel corpo della richiesta. Ad esempio, scope=read:payment write:payment. Tratteremo gli scope più avanti.

Ecco un esempio della richiesta usando curl:

Un corpo di risposta positivo sarebbe come:

Invia richiesta con header di autorizzazione

Ora abbiamo il token di accesso e possiamo aggiungerlo all'header Authorization della richiesta alla risorsa API. Ad esempio, se vogliamo chiamare l'API POST /payments del servizio di pagamento, possiamo inviare la seguente richiesta:

Valida JWT

Potresti notare che il servizio di pagamento deve convalidare il JWT usando il set JWK e potrebbe avere una cache di set JWK locale per evitare di recuperare il set JWK da Logto ogni volta. Fortunatamente, a causa della popolarità di JWT, ci sono molte librerie che possono aiutarti a raggiungere l'obiettivo con poche righe di codice.

Queste librerie sono solitamente chiamate "jose" (JavaScript Object Signing and Encryption) o "jsonwebtoken". Per esempio, in Node.js possiamo usare jose per convalidare il JWT:

Se la validazione riesce, la variabile payload sarà il payload JWT decodificato. Altrimenti, verrà generato un errore.

Applica il controllo degli accessi basato sui ruoli

Ora abbiamo protetto con successo la comunicazione tra il servizio carrello e il servizio di pagamento. Tuttavia, il flusso di autenticazione assicura solo che il client sia il vero servizio carrello, ma non garantisce che il servizio carrello abbia qualsivoglia permesso di eseguire azioni sul servizio di pagamento.

Supponiamo di voler consentire al servizio carrello di creare pagamenti, ma non di leggere pagamenti.

Definisci i permessi

In Logto, "scope" e "permessi" sono intercambiabili. Vai alla pagina dei dettagli della risorsa API del servizio di pagamento e naviga alla scheda Permessi. Dovrebbe essere vuota ora. Fai clic su Crea permesso, inserisci read:payment come nome del permesso e Leggi pagamenti come descrizione del permesso. Quindi, fai clic su Crea permesso.

Ripeti i passaggi sopra per creare un altro permesso con il nome write:payment e la descrizione Crea pagamenti.

Crea ruolo da macchina a macchina

Un ruolo è un gruppo di permessi. In Logto, le app da macchina a macchina possono essere assegnate a ruoli per concedere permessi. Clicca su "Ruoli" nella barra laterale a sinistra e clicca su Crea ruolo.

  1. Inserisci checkout come nome del ruolo e Servizio di Checkout come descrizione del ruolo.
  2. Clicca su Mostra più opzioni. Scegli "Ruolo app da macchina a macchina" come tipo di ruolo.
  3. Nella sezione "Permessi assegnati", clicca sull'icona a freccia a sinistra del nome della risorsa API (Servizio di Pagamento) e seleziona il permesso write:payment.
    Crea ruolo
  4. Clicca su Crea ruolo.
  5. Poiché abbiamo già un'app da macchina a macchina (Servizio Carrello), possiamo assegnarvi direttamente il ruolo nel passaggio successivo. Seleziona la casella di controllo a sinistra del nome dell'app (Servizio Carrello) e clicca su Assegna applicazioni.
Assegna ruolo all'applicazione

Richiedi token di accesso con scope

Oltre ai parametri del corpo della richiesta menzionati in Richiedi token di accesso, possiamo anche specificare gli scope nel corpo della richiesta. Ad esempio, se vogliamo richiedere il permesso write:payment, possiamo inviare la seguente richiesta:

Per richiedere più scope, puoi separarli con spazi. Ad esempio, scope=write:payment read:payment.

Valida gli scope

Se un'azione ha bisogno del permesso write:payment nel servizio di pagamento, possiamo convalidare gli scope affermando che il claim scope del payload JWT:

Conclusione

Se vuoi proteggere l'accesso al servizio carrello, puoi anche applicare lo stesso flusso di autenticazione. Questa volta, il servizio carrello è la risorsa API e il client è un altro servizio che necessita di accesso.

Con Logto, le tue risorse API sono protette con OAuth 2.0 e JWT, e puoi seguire il principio del privilegio minimo applicando il controllo degli accessi basato sui ruoli. Inoltre, puoi anche usare Logto per gestire i tuoi utenti e i loro permessi e persino integrarti con provider di identità di terze parti.