primo piano
Stiamo passando da una piattaforma monolitica a un'architettura Service Oriented. Stiamo applicando principi DDD di base e suddividendo il nostro dominio in diversi contesti limitati. Ogni dominio è distribuito ed espone un servizio tramite un'API web (REST).
A causa della natura della nostra attività, abbiamo servizi come Prenotazioni , Servizi , Clienti , Prodotti , ecc.
Abbiamo anche creato un Identity Server (basato su Thinktecture Identity Server 3) il cui ruolo principale è:
- centralizza l'autenticazione (le credenziali fornite emettono i token)
- Aggiungi rivendicazioni nei token come: gli ambiti del client (come per client intendo l'applicazione che esegue la richiesta), identificativo del cliente (come per cliente intendo la persona che utilizza l'applicazione)
Abbiamo anche introdotto il ruolo di un gateway API che centralizza l'accesso esterno ai nostri servizi. Il gateway API fornisce funzionalità che non richiedono una conoscenza approfondita dei domini interni come:
- Reverse proxy: instrada le richieste in entrata nel servizio interno appropriato
- Controllo versioni: una versione del gateway API esegue il mapping a diverse versioni dei servizi interni
- Autenticazione: le richieste client includono il token emesso da Identity Server e il gateway API convalida il token (assicurati che l'utente sia chi dice di essere)
- Limitazione: numero limite di richieste per client
Autorizzazione
Ciò che riguarda l'autorizzazione, questo non è gestito nel gateway API ma nei servizi interni stessi. Al momento stiamo eseguendo 2 principali tipi di autorizzazione:
- Autorizzazione basata sugli ambiti client. Esempio: un client (un'applicazione esterna che consuma le nostre API) richiede l'ambito "prenotazioni" per accedere agli endpoint dell'API Bookings
- Autorizzazione basata sul cliente. Esempio: solo se un cliente (persona fisica che utilizza l'applicazione) è un partecipante di una prenotazione può accedere all'endpoint GET / prenotazioni dal servizio Prenotazioni
Per essere in grado di gestire l'autorizzazione nei servizi interni, il gateway API inoltra semplicemente il token (quando instradare la richiesta al servizio interno) che include sia le informazioni sul client (l'applicazione che esegue la richiesta) che il cliente come reclamo (in quei casi in cui una persona è registrata nell'applicazione client).
Descrizione del problema
Fin qui tutto bene fino a quando non abbiamo introdotto la comunicazione tra servizi (alcuni servizi possono comunicare con altri servizi per ottenere alcuni dati).
Domanda
Come dovremmo avvicinarci all'autorizzazione nelle comunicazioni tra servizi?
Opzioni considerate
Per discutere le diverse opzioni userò il seguente scenario di esempio:
- Abbiamo un'applicazione esterna chiamata ExternalApp che accede alla nostra API ( ExternalApp può essere vista come il client ) per creare la prenotazione flusso
- ExternalApp richiede l'accesso al servizio Bookings , quindi garantiamo ExternalApp the scope "bookings"
- Internamente (questo è qualcosa di completamente trasparente per ExternalApp ) il servizio Bookings accede al servizio Servizi per ottenere i servizi predefiniti di una prenotazione come i voli, le assicurazioni o un autonoleggio
Quando discuti questo problema internamente sono spuntate diverse opzioni, ma non siamo sicuri quale sia l'opzione migliore:
- Quando Prenotazioni comunica con Servizi , deve semplicemente inoltrare il token originale che ha ricevuto dal gateway API (che indica che il client è ExternalApp )
- Implicazioni: potrebbe essere necessario concedere gli ambiti a ExternalApp che non avrebbero dovuto essere concessi. Esempio: ExternalApp potrebbe aver bisogno di avere entrambe le "prenotazioni" di scope e "servizi", mentre solo l'ambito "prenotazioni" poteva essere sufficiente
- Quando Prenotazioni comunica con Servizi , inoltra un token che indica che il client ora è diventato Prenotazioni (invece di ExternalApp ) + aggiunge un reclamo che indica Bookings sta impersonando il client originale ExternalApp
- Includendo anche le informazioni che il client originale è ExternalApp il servizio Servizi potrebbe anche fare logiche come filtrare alcuni servizi a seconda del chiamante originale (ad es. app interne dovremmo restituire tutti i combattimenti, solo per alcune app esterne)
- I servizi non dovrebbero comunicare tra loro (quindi non dovremmo nemmeno essere di fronte a questa domanda)
Grazie in anticipo per il tuo contributo.