Condividi tramite


Implementare gateway API con Ocelot

Suggerimento

Questo contenuto è un estratto dell'eBook, Architettura di microservizi .NET per applicazioni .NET containerizzati, disponibile in documentazione .NET o come PDF scaricabile gratuitamente leggibile offline.

Architettura di Microservizi .NET per Applicazioni .NET Containerizzate miniatura della copertina dell'eBook.

Importante

L'applicazione di microservizi di riferimento eShopOnContainers usa attualmente le funzionalità fornite da Envoy per implementare il gateway API anziché il precedente Ocelot a cui si fa riferimento. Questa scelta di progettazione è stata effettuata a causa del supporto predefinito di Envoy per il protocollo WebSocket, richiesto dalla nuova comunicazione tra servizi gRPC implementata in eShopOnContainers. Tuttavia, questa sezione è stata mantenuta nella guida in modo da poter considerare Ocelot come un gateway API semplice, in grado di supportare e leggero adatto per scenari di livello di produzione. Inoltre, la versione più recente di Ocelot contiene una modifica che causa un'interruzione dello schema JSON. Prendere in considerazione l'uso di Ocelot < v16.0.0 o usare le route chiave invece di ReRoutes.

Progettare e progettare i gateway API

Il diagramma dell'architettura seguente illustra come i gateway API sono stati implementati con Ocelot in eShopOnContainers.

Diagramma che mostra l'architettura di eShopOnContainers.

Figura 6-28. Architettura eShopOnContainers con gateway API

Questo diagramma mostra come l'intera applicazione viene distribuita in un singolo host Docker o in un singolo PC di sviluppo con "Docker per Windows" o "Docker per Mac". Tuttavia, la distribuzione in qualsiasi agente di orchestrazione sarebbe simile, ma qualsiasi contenitore nel diagramma potrebbe essere a scalabilità orizzontale nell'agente di orchestrazione.

Inoltre, gli asset dell'infrastruttura, ad esempio database, cache e broker di messaggi, devono essere scaricati dall'agente di orchestrazione e distribuiti in sistemi a disponibilità elevata per l'infrastruttura, ad esempio database SQL di Azure, Azure Cosmos DB, Azure Redis, bus di servizio di Azure o qualsiasi soluzione di clustering a disponibilità elevata in locale.

Come si può notare anche nel diagramma, la presenza di diversi gateway API consente a più team di sviluppo di essere autonomi (in questo caso funzionalità di marketing e funzionalità di shopping) durante lo sviluppo e la distribuzione dei propri microservizi e dei relativi gateway API correlati.

Se si dispone di un singolo gateway API monolitico che significa un singolo punto da aggiornare da diversi team di sviluppo, che potrebbero associare tutti i microservizi a una singola parte dell'applicazione.

Andando molto più avanti nella progettazione, a volte un gateway API con granularità fine può anche essere limitato a un singolo microservizio aziendale a seconda dell'architettura scelta. La presenza dei limiti del gateway API dettata dall'azienda o dal dominio consente di ottenere una progettazione migliore.

Ad esempio, la granularità fine nel livello gateway API può essere particolarmente utile per applicazioni di interfaccia utente composite più avanzate basate su microservizi, perché il concetto di gateway API con granularità fine è simile a un servizio di composizione dell'interfaccia utente.

Altre informazioni sono disponibili nella sezione precedente Creazione di un'interfaccia utente composita basata su microservizi.

Come fattore chiave, per molte applicazioni di medie e grandi dimensioni, l'uso di un prodotto Gateway API personalizzato è in genere un buon approccio, ma non come singolo aggregatore monolitico o un gateway API centrale univoco, a meno che il gateway API non consenta più aree di configurazione indipendenti per i diversi team di sviluppo che creano microservizi autonomi.

Microservizi/contenitori di esempio da reindirizzare tramite i gateway API

Ad esempio, eShopOnContainers ha circa sei tipi di microservizi interni che devono essere pubblicati tramite i gateway API, come illustrato nell'immagine seguente.

Screenshot della cartella Servizi che mostra le relative sottocartelle.

Figura 6-29. Cartelle di microservizi nella soluzione eShopOnContainers in Visual Studio

Informazioni sul servizio di gestione delle identità, nella progettazione è rimasto fuori dal routing del gateway API perché è l'unico problema trasversale nel sistema, anche se con Ocelot è anche possibile includerlo come parte degli elenchi di reindirizzamento.

Tutti questi servizi sono attualmente implementati come servizi API Web di base ASP.NET, come è possibile indicare dal codice. Si esaminerà ora uno dei microservizi, ad esempio il codice del microservizio Catalog.

Screenshot di Esplora soluzioni che mostra il contenuto del progetto Catalog.API.

Figura 6-30. Microservizio API Web di esempio (microservizio catalogo)

È possibile notare che il microservizio Catalog è un tipico progetto API Web di ASP.NET Core con diversi controller e metodi come nel codice seguente.

[HttpGet]
[Route("items/{id:int}")]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(CatalogItem),(int)HttpStatusCode.OK)]
public async Task<IActionResult> GetItemById(int id)
{
    if (id <= 0)
    {
        return BadRequest();
    }
    var item = await _catalogContext.CatalogItems.
                                          SingleOrDefaultAsync(ci => ci.Id == id);
    //…

    if (item != null)
    {
        return Ok(item);
    }
    return NotFound();
}

La richiesta HTTP finirà per l'esecuzione di quel tipo di codice C# che accede al database di microservizi ed eventuali azioni aggiuntive necessarie.

Per quanto riguarda l'URL del microservizio, quando i contenitori vengono distribuiti nel PC di sviluppo locale (host Docker locale), ogni contenitore del microservizio ha sempre una porta interna (in genere la porta 80) specificata nel relativo dockerfile, come nel dockerfile seguente:

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80

La porta 80 visualizzata nel codice è interna all'interno dell'host Docker, quindi non può essere raggiunta dalle app client.

Le app client possono accedere solo alle porte esterne (se presenti) pubblicate durante la distribuzione con docker-compose.

Queste porte esterne non devono essere pubblicate durante la distribuzione in un ambiente di produzione. Per questo motivo specifico, perché si vuole usare il gateway API, per evitare la comunicazione diretta tra le app client e i microservizi.

Tuttavia, durante lo sviluppo, si vuole accedere direttamente al microservizio o al contenitore ed eseguirlo tramite Swagger. Ecco perché in eShopOnContainers le porte esterne vengono ancora specificate anche quando non verranno usate dal gateway API o dalle app client.

Ecco un esempio del docker-compose.override.yml file per il microservizio Catalog:

catalog-api:
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - ASPNETCORE_URLS=http://0.0.0.0:80
    - ConnectionString=YOUR_VALUE
    - ... Other Environment Variables
  ports:
    - "5101:80"   # Important: In a production environment you should remove the external port (5101) kept here for microservice debugging purposes.
                  # The API Gateway redirects and access through the internal port (80).

È possibile vedere come nella configurazione docker-compose.override.yml la porta interna per il contenitore catalog è la porta 80, ma la porta per l'accesso esterno è 5101. Tuttavia, questa porta non deve essere usata dall'applicazione quando si usa un gateway API, solo per eseguire il debug, l'esecuzione e testare solo il microservizio Catalog.

In genere, non verrà eseguita la distribuzione con docker-compose in un ambiente di produzione perché l'ambiente di distribuzione di produzione appropriato per i microservizi è un agente di orchestrazione come Kubernetes o Service Fabric. Quando si esegue la distribuzione in tali ambienti si usano file di configurazione diversi in cui non si pubblicherà direttamente alcuna porta esterna per i microservizi, ma si userà sempre il proxy inverso dal gateway API.

Eseguire il microservizio catalogo nell'host Docker locale. Eseguire la soluzione completa eShopOnContainers da Visual Studio (esegue tutti i servizi nei file docker-compose) oppure avviare il microservizio Catalog con il comando docker-compose seguente in CMD o PowerShell posizionato nella cartella in cui docker-compose.yml sono posizionati e docker-compose.override.yml .

docker-compose run --service-ports catalog-api

Questo comando esegue solo il contenitore del servizio catalog-api e le dipendenze specificate nella docker-compose.yml. In questo caso, il contenitore SQL Server e il contenitore RabbitMQ.

È quindi possibile accedere direttamente al microservizio Catalog e visualizzarne i metodi tramite l'interfaccia utente di Swagger che accede direttamente tramite tale porta "esterna", in questo caso http://host.docker.internal:5101/swagger:

Screenshot dell'interfaccia utente di Swagger che mostra l'API REST Catalog.API.

Figura 6-31. Test del microservizio Catalog con l'interfaccia utente di Swagger

A questo punto, è possibile impostare un punto di interruzione nel codice C# in Visual Studio, testare il microservizio con i metodi esposti nell'interfaccia utente di Swagger e infine pulire tutto con il docker-compose down comando .

Tuttavia, la comunicazione con accesso diretto al microservizio, in questo caso tramite la porta esterna 5101, è esattamente ciò che si vuole evitare nell'applicazione. È anche possibile evitare questo problema impostando il livello aggiuntivo di riferimento indiretto del gateway API (Ocelot, in questo caso). In questo modo, l'app client non accederà direttamente al microservizio.

Implementazione dei gateway API con Ocelot

Ocelot è fondamentalmente un set di middleware che è possibile applicare in un ordine specifico.

Ocelot è progettato per funzionare solo con ASP.NET Core. La versione più recente del pacchetto è 18.0 destinata a .NET 6 e pertanto non è adatta per le applicazioni .NET Framework.

È possibile installare Ocelot e le relative dipendenze nel progetto ASP.NET Core con il pacchetto NuGet di Ocelot da Visual Studio.

Install-Package Ocelot

In eShopOnContainers, l'implementazione del gateway API è un semplice progetto WebHost di ASP.NET Core e il middleware di Ocelot gestisce tutte le funzionalità del gateway API, come illustrato nell'immagine seguente:

Screenshot di Esplora soluzioni che mostra il progetto gateway API Ocelot.

Figura 6-32. Progetto di base OcelotApiGw in eShopOnContainers

Questo ASP.NET progetto WebHost core viene compilato con due file semplici: Program.cs e Startup.cs.

Il Program.cs deve solo creare e configurare il tipico ASP.NET Core BuildWebHost.

namespace OcelotApiGw
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args)
        {
            var builder = WebHost.CreateDefaultBuilder(args);

            builder.ConfigureServices(s => s.AddSingleton(builder))
                    .ConfigureAppConfiguration(
                          ic => ic.AddJsonFile(Path.Combine("configuration",
                                                            "configuration.json")))
                    .UseStartup<Startup>();
            var host = builder.Build();
            return host;
        }
    }
}

Il punto importante qui per Ocelot è il configuration.json file che è necessario fornire al generatore tramite il AddJsonFile() metodo . In questo configuration.json caso si specificano tutti i reindirizzamenti del gateway API, ovvero gli endpoint esterni con porte specifiche e gli endpoint interni correlati, in genere usando porte diverse.

{
    "ReRoutes": [],
    "GlobalConfiguration": {}
}

Esistono due sezioni per la configurazione. Matrice di ReRoutes e GlobalConfiguration. ReRoutes sono gli oggetti che indicano a Ocelot come gestire una richiesta upstream. La configurazione globale consente di eseguire l'override delle impostazioni specifiche di ReRoute. È utile se non si vogliono gestire molte impostazioni specifiche di ReRoute.

Ecco un esempio semplificato di file di configurazione di ReRoute da uno dei gateway API di eShopOnContainers.

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/{version}/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "catalog-api",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/api/{version}/c/{everything}",
      "UpstreamHttpMethod": [ "POST", "PUT", "GET" ]
    },
    {
      "DownstreamPathTemplate": "/api/{version}/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "basket-api",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/api/{version}/b/{everything}",
      "UpstreamHttpMethod": [ "POST", "PUT", "GET" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "IdentityApiKey",
        "AllowedScopes": []
      }
    }

  ],
    "GlobalConfiguration": {
      "RequestIdKey": "OcRequestId",
      "AdministrationPath": "/administration"
    }
  }

La funzionalità principale di un gateway API Ocelot consiste nell'accettare le richieste HTTP in ingresso e inoltrarle a un servizio downstream, attualmente come un'altra richiesta HTTP. Ocelot descrive il routing di una richiesta a un'altra come ReRoute.

Ad esempio, è possibile concentrarsi su una delle route nella configuration.json precedente, la configurazione per il microservizio Basket.

{
      "DownstreamPathTemplate": "/api/{version}/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "basket-api",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/api/{version}/b/{everything}",
      "UpstreamHttpMethod": [ "POST", "PUT", "GET" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "IdentityApiKey",
        "AllowedScopes": []
      }
}

DownstreamPathTemplate, Scheme e DownstreamHostAndPorts rendono l'URL del microservizio interno a cui verrà inoltrata la richiesta.

La porta è la porta interna usata dal servizio. Quando si usano contenitori, la porta specificata nel relativo dockerfile.

Host è un nome di servizio che dipende dalla risoluzione dei nomi del servizio in uso. Quando si usa docker-compose, i nomi dei servizi vengono forniti dall'host Docker, che usa i nomi dei servizi forniti nei file docker-compose. Se si usa un agente di orchestrazione come Kubernetes o Service Fabric, tale nome deve essere risolto dalla risoluzione DNS o dei nomi fornita da ogni agente di orchestrazione.

DownstreamHostAndPorts è una matrice che contiene l'host e la porta di tutti i servizi downstream a cui si desidera inoltrare le richieste. In genere questa configurazione conterrà solo una voce, ma a volte potrebbe essere necessario bilanciare il carico delle richieste ai servizi downstream e Ocelot consente di aggiungere più di una voce e quindi selezionare un servizio di bilanciamento del carico. Tuttavia, se si usa Azure e qualsiasi agente di orchestrazione, è probabilmente preferibile bilanciare il carico con l'infrastruttura cloud e dell'agente di orchestrazione.

UpstreamPathTemplate è l'URL che Ocelot userà per identificare quale DownstreamPathTemplate usare per una determinata richiesta dal client. Viene infine usato UpstreamHttpMethod in modo che Ocelot possa distinguere tra richieste diverse (GET, POST, PUT) allo stesso URL.

A questo punto, è possibile avere un singolo gateway API Ocelot (ASP.NET Core WebHost) usando uno o più file di configuration.json uniti oppure è anche possibile archiviare la configurazione in un archivio KV Consul.

Tuttavia, come illustrato nelle sezioni architettura e progettazione, se si vuole avere microservizi autonomi, potrebbe essere preferibile suddividere tale singolo gateway API monolitico in più gateway API e/o BFF (back-end per front-end). A tale scopo, verrà illustrato come implementare questo approccio con i contenitori Docker.

Uso di una singola immagine del contenitore Docker per eseguire più tipi di contenitore BFF/Gateway API diversi

In eShopOnContainers viene usata una singola immagine del contenitore Docker con il gateway API Ocelot, ma in fase di esecuzione vengono creati servizi/contenitori diversi per ogni tipo di API-Gateway/BFF fornendo un file di configuration.json diverso, usando un volume Docker per accedere a una cartella PC diversa per ogni servizio.

Diagramma di una singola immagine Docker del gateway Ocelot per tutti i gateway API.

Figura 6-33. Riutilizzo di una singola immagine Docker Ocelot tra più tipi di gateway API

In eShopOnContainers, viene creato "Generic Ocelot API Gateway Docker Image" con il progetto denominato "OcelotApiGw" e il nome dell'immagine "eshop/ocelotapigw" specificato nel file docker-compose.yml. Quindi, quando si esegue la distribuzione in Docker, saranno presenti quattro contenitori API-Gateway creati dalla stessa immagine Docker, come illustrato nell'estratto seguente dal file docker-compose.yml.

  mobileshoppingapigw:
    image: eshop/ocelotapigw:${TAG:-latest}
    build:
      context: .
      dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile

  mobilemarketingapigw:
    image: eshop/ocelotapigw:${TAG:-latest}
    build:
      context: .
      dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile

  webshoppingapigw:
    image: eshop/ocelotapigw:${TAG:-latest}
    build:
      context: .
      dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile

  webmarketingapigw:
    image: eshop/ocelotapigw:${TAG:-latest}
    build:
      context: .
      dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile

Inoltre, come si può notare nel file di docker-compose.override.yml seguente, l'unica differenza tra questi contenitori del gateway API è il file di configurazione Ocelot, che è diverso per ogni contenitore del servizio e viene specificato in fase di esecuzione tramite un volume Docker.

mobileshoppingapigw:
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - IdentityUrl=http://identity-api
  ports:
    - "5200:80"
  volumes:
    - ./src/ApiGateways/Mobile.Bff.Shopping/apigw:/app/configuration

mobilemarketingapigw:
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - IdentityUrl=http://identity-api
  ports:
    - "5201:80"
  volumes:
    - ./src/ApiGateways/Mobile.Bff.Marketing/apigw:/app/configuration

webshoppingapigw:
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - IdentityUrl=http://identity-api
  ports:
    - "5202:80"
  volumes:
    - ./src/ApiGateways/Web.Bff.Shopping/apigw:/app/configuration

webmarketingapigw:
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - IdentityUrl=http://identity-api
  ports:
    - "5203:80"
  volumes:
    - ./src/ApiGateways/Web.Bff.Marketing/apigw:/app/configuration

A causa di questo codice precedente e come illustrato in Visual Studio Explorer di seguito, l'unico file necessario per definire ogni gateway API business/BFF specifico è solo un file configuration.json, perché i quattro gateway API si basano sulla stessa immagine Docker.

Screenshot che mostra tutti i gateway API con configuration.json file.

Figura 6-34. L'unico file necessario per definire ogni gateway API/BFF con Ocelot è un file di configurazione

Suddividendo il gateway API in più gateway API, diversi team di sviluppo incentrati su subset diversi di microservizi possono gestire i propri gateway API usando file di configurazione Ocelot indipendenti. Inoltre, allo stesso tempo possono riutilizzare la stessa immagine Docker Ocelot.

Ora, se si esegue eShopOnContainers con i gateway API (inclusi per impostazione predefinita in Visual Studio quando si apre eShopOnContainers-ServicesAndWebApps.sln soluzione o se si esegue "docker-compose up"), verranno eseguite le route di esempio seguenti.

Ad esempio, quando si visita l'URL http://host.docker.internal:5202/api/v1/c/catalog/items/2/ upstream gestito dal gateway API webshoppingapigw, si ottiene lo stesso risultato dall'URL http://catalog-api/api/v1/2 downstream interno all'interno dell'host Docker, come nel browser seguente.

Screenshot di un browser che mostra una risposta che passa attraverso il gateway API.

Figura 6-35. Accesso a un microservizio tramite un URL fornito dal gateway API

Per motivi di test o debug, se si vuole accedere direttamente al contenitore Docker del catalogo (solo nell'ambiente di sviluppo) senza passare attraverso il gateway API, poiché "catalog-api" è una risoluzione DNS interna all'host Docker (individuazione del servizio gestita dai nomi dei servizi docker-compose), l'unico modo per accedere direttamente al contenitore è tramite la porta esterna pubblicata nel docker-compose.override.yml, disponibile solo per i test di sviluppo, ad esempio http://host.docker.internal:5101/api/v1/Catalog/items/1 nel browser seguente.

Screenshot di un browser che mostra una risposta diretta a Catalog.api.

Figura 6-36. Accesso diretto a un microservizio a scopo di test

Ma l'applicazione è configurata in modo da accedere a tutti i microservizi tramite i gateway API, non tramite la porta diretta "collegamenti".

Modello di aggregazione gateway in eShopOnContainers

Come introdotto in precedenza, un modo flessibile per implementare l'aggregazione delle richieste è con servizi personalizzati, in base al codice. Il modo selezionato per implementare l'aggregazione in eShopOnContainers è costituito da un servizio API Web core ASP.NET esplicito per ogni aggregatore.

In base a questo approccio, il diagramma di composizione del gateway API è in realtà un po' più esteso quando si considerano i servizi di aggregatore non visualizzati nel diagramma dell'architettura globale semplificato illustrato in precedenza.

Nel diagramma seguente è anche possibile vedere come funzionano i servizi di aggregatore con i gateway API correlati.

Diagramma dell'architettura di eShopOnContainers che mostra i servizi di aggregatore.

Figura 6-37. Architettura eShopOnContainers con servizi aggregatori

Se si esegue lo zoom avanti, nell'area aziendale "Shopping" nell'immagine seguente è possibile osservare che la messaggistica tra le app client e i microservizi viene ridotta quando si usano i servizi di aggregatore nei gateway API.

Diagramma che mostra lo zoom avanti dell'architettura di eShopOnContainers.

Figura 6-38. Ingrandire la visione dei servizi aggregatori

È possibile notare come quando il diagramma mostra le possibili richieste provenienti dai gateway API che può diventare complesso. D'altra parte, quando si usa il modello di aggregatore, è possibile vedere come le frecce in blu semplificano la comunicazione dal punto di vista di un'app client. Questo modello non solo consente di ridurre la chattiness e la latenza nella comunicazione, ma migliora anche l'esperienza utente significativamente per le app remote (app per dispositivi mobili e spa).

Nel caso dell'area aziendale "Marketing" e dei microservizi, si tratta di un caso d'uso semplice, quindi non è necessario usare aggregatori, ma potrebbe anche essere possibile, se necessario.

Autenticazione e autorizzazione nei gateway API Ocelot

In un gateway API Ocelot è possibile sedersi nel servizio di autenticazione, ad esempio un servizio API Web core di ASP.NET usando IdentityServer che fornisce il token di autenticazione, all'esterno o all'interno del gateway API.

Poiché eShopOnContainers usa più gateway API con limiti basati su BFF e aree aziendali, il servizio Identity/Auth viene lasciato fuori dai gateway API, come evidenziato in giallo nel diagramma seguente.

Diagramma che mostra il microservizio Identity sotto il gateway API.

Figura 6-39. Posizione del servizio Identity in eShopOnContainers

Tuttavia, Ocelot supporta anche il microservizio Identity/Auth entro il limite del gateway API, come in questo altro diagramma.

Diagramma che mostra l'autenticazione in un gateway API Ocelot.

Figura 6-40. Autenticazione in Ocelot

Come illustrato nel diagramma precedente, quando il microservizio Identity si trova sotto il gateway API (AG): 1) il gruppo di disponibilità richiede un token di autenticazione dal microservizio identity, 2) Il microservizio identity restituisce il token al gruppo di disponibilità, 3-4) richieste di gruppo di disponibilità dai microservizi usando il token di autenticazione. Poiché l'applicazione eShopOnContainers ha suddiviso il gateway API in più gateway API BFF (back-end per front-end) e aree aziendali, un'altra opzione sarebbe stata quella di creare un gateway API aggiuntivo per problemi trasversali. Questa scelta sarebbe equa in un'architettura più complessa basata su microservizi con più problemi trasversali di microservizi. Poiché c'è solo una preoccupazione trasversale in eShopOnContainers, è stato deciso di gestire solo il servizio di sicurezza dall'area di autenticazione del gateway API, per semplicità.

In ogni caso, se l'app è protetta a livello di gateway API, il modulo di autenticazione del gateway API Ocelot viene visitato inizialmente quando si tenta di usare qualsiasi microservizio protetto. Che reindirizza la richiesta HTTP per visitare il microservizio Identity o auth per ottenere il token di accesso in modo da poter visitare i servizi protetti con il access_token.

Il modo in cui si protegge con l'autenticazione qualsiasi servizio a livello di gateway API consiste nell'impostare AuthenticationProviderKey nelle relative impostazioni nel configuration.json.

    {
      "DownstreamPathTemplate": "/api/{version}/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "basket-api",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/api/{version}/b/{everything}",
      "UpstreamHttpMethod": [],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "IdentityApiKey",
        "AllowedScopes": []
      }
    }

Durante l'esecuzione di Ocelot, esaminerà ReRoutes AuthenticationOptions.AuthenticationProviderKey e verificherà che sia presente un provider di autenticazione registrato con la chiave specificata. In caso contrario, Ocelot non verrà avviato. In caso affermativo, il reroute userà tale provider quando viene eseguito.

Poiché Ocelot WebHost è configurato con authenticationProviderKey = "IdentityApiKey", che richiederà l'autenticazione ogni volta che il servizio ha richieste senza token di autenticazione.

namespace OcelotApiGw
{
    public class Startup
    {
        private readonly IConfiguration _cfg;

        public Startup(IConfiguration configuration) => _cfg = configuration;

        public void ConfigureServices(IServiceCollection services)
        {
            var identityUrl = _cfg.GetValue<string>("IdentityUrl");
            var authenticationProviderKey = "IdentityApiKey";
                         //…
            services.AddAuthentication()
                .AddJwtBearer(authenticationProviderKey, x =>
                {
                    x.Authority = identityUrl;
                    x.RequireHttpsMetadata = false;
                    x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
                    {
                        ValidAudiences = new[] { "orders", "basket", "locations", "marketing", "mobileshoppingagg", "webshoppingagg" }
                    };
                });
            //...
        }
    }
}

È quindi necessario impostare l'autorizzazione con l'attributo [Authorize] per qualsiasi risorsa a cui accedere come i microservizi, ad esempio nel controller di microservizi Basket seguente.

namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{
    [Route("api/v1/[controller]")]
    [Authorize]
    public class BasketController : Controller
    {
      //...
    }
}

Gli oggetti ValidAudience, ad esempio "basket", sono correlati al gruppo di destinatari definito in ogni microservizio con AddJwtBearer() alla classe ConfigureServices() della classe Startup, ad esempio nel codice seguente.

// prevent from mapping "sub" claim to nameidentifier.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

var identityUrl = Configuration.GetValue<string>("IdentityUrl");

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

}).AddJwtBearer(options =>
{
    options.Authority = identityUrl;
    options.RequireHttpsMetadata = false;
    options.Audience = "basket";
});

Se si tenta di accedere a qualsiasi microservizio protetto, ad esempio il microservizio Basket con un URL ReRoute basato sul gateway API come http://host.docker.internal:5202/api/v1/b/basket/1, si otterrà un 401 Non autorizzato a meno che non si fornisca un token valido. D'altra parte, se viene autenticato un URL di ReRoute, Ocelot richiamerà qualsiasi schema downstream a esso associato (l'URL del microservizio interno).

Autorizzazione al livello ReRoutes di Ocelot. Ocelot supporta l'autorizzazione basata sulle attestazioni valutata dopo l'autenticazione. Per impostare l'autorizzazione a livello di route, aggiungere le righe seguenti alla configurazione di ReRoute.

"RouteClaimsRequirement": {
    "UserType": "employee"
}

In questo esempio, quando viene chiamato il middleware di autorizzazione, Ocelot troverà se l'utente ha il tipo di attestazione 'UserType' nel token e se il valore di tale attestazione è 'employee'. In caso contrario, l'utente non sarà autorizzato e la risposta sarà 403 non consentita.

Uso di Kubernetes Ingress plus Ocelot API Gateways (Uso di Kubernetes Ingress e gateway API Ocelot)

Quando si usa Kubernetes (ad esempio in un cluster del servizio Azure Kubernetes), in genere si unificano tutte le richieste HTTP tramite il livello di ingresso Kubernetes basato su Nginx.

In Kubernetes, se non si usa alcun approccio in ingresso, i servizi e i pod hanno indirizzi IP instradabili solo dalla rete del cluster.

Tuttavia, se si usa un approccio in ingresso, si avrà un livello intermedio tra Internet e i servizi (inclusi i gateway API), che funge da proxy inverso.

Come definizione, un ingresso è una raccolta di regole che consentono alle connessioni in ingresso di raggiungere i servizi cluster. Un ingresso è configurato per fornire servizi URL raggiungibili esternamente, bilanciare il carico del traffico, la terminazione SSL e altro ancora. Gli utenti richiedono l'ingresso POSTing the Ingress resource to the API server (Richiedi ingresso) al server API.

In eShopOnContainers, quando si sviluppa in locale e si usa solo il computer di sviluppo come host Docker, non si usano dati in ingresso, ma solo più gateway API.

Tuttavia, quando la destinazione è un ambiente di "produzione" basato su Kubernetes, eShopOnContainers usa un ingresso davanti ai gateway API. In questo modo, i client chiamano ancora lo stesso URL di base, ma le richieste vengono instradate a più gateway API o BFF.

I gateway API sono front-end o facciata che espongono solo i servizi, ma non le applicazioni Web che in genere non rientrano nell'ambito. Inoltre, i gateway API potrebbero nascondere determinati microservizi interni.

L'ingresso, tuttavia, reindirizza solo le richieste HTTP, ma non tenta di nascondere qualsiasi microservizio o app Web.

Avere un livello Nginx in ingresso in Kubernetes davanti alle applicazioni Web più i diversi gateway API Ocelot/BFF è l'architettura ideale, come illustrato nel diagramma seguente.

Diagramma che mostra il modo in cui un livello di ingresso rientra nell'ambiente del servizio Azure Kubernetes.

Figura 6-41. Livello di ingresso in eShopOnContainers quando viene distribuito in Kubernetes

Un ingresso Kubernetes funge da proxy inverso per tutto il traffico verso l'app, incluse le applicazioni Web, che non rientrano nell'ambito del gateway API. Quando si distribuisce eShopOnContainers in Kubernetes, vengono esposti solo alcuni servizi o endpoint tramite ingresso, fondamentalmente l'elenco seguente di postfissi negli URL:

  • / per l'applicazione Web a pagina singola client
  • /webmvc per l'applicazione Web MVC client
  • /webstatus per l'app Web client che mostra lo stato/controlli di integrità
  • /webshoppingapigw per il Web BFF e i processi aziendali di acquisto
  • /webmarketingapigw per il web BFF e i processi aziendali di marketing
  • /mobileshoppingapigw per i processi aziendali per dispositivi mobili BFF e shopping
  • /mobilemarketingapigw per i processi aziendali per dispositivi mobili BFF e marketing

Quando si esegue la distribuzione in Kubernetes, ogni gateway API Ocelot usa un file "configuration.json" diverso per ogni pod che esegue i gateway API. Tali file "configuration.json" vengono forniti tramite il montaggio (originariamente con lo script deploy.ps1) un volume creato in base a una mappa di configurazione kubernetes denominata 'ocelot'. Ogni contenitore monta il file di configurazione correlato nella cartella del contenitore denominata /app/configuration.

Nei file di codice sorgente di eShopOnContainers i file originali "configuration.json" sono disponibili all'interno della k8s/ocelot/ cartella . Esiste un file per ogni BFF/APIGateway.

Funzionalità di taglio incrociato aggiuntive in un gateway API Ocelot

Esistono altre funzionalità importanti da cercare e usare, quando si usa un gateway API Ocelot, descritto nei collegamenti seguenti.