Partilhar via


Implementar gateways de API com jaguatirica

Gorjeta

Este conteúdo é um trecho do eBook, .NET Microservices Architecture for Containerized .NET Applications, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Importante

O aplicativo de microsserviço de referência eShopOnContainers está atualmente usando recursos fornecidos pelo Envoy para implementar o API Gateway em vez da jaguatirica referenciada anteriormente. Fizemos essa escolha de design devido ao suporte integrado do Envoy para o protocolo WebSocket, exigido pelas novas comunicações interserviços gRPC implementadas no eShopOnContainers. No entanto, mantivemos esta seção no guia para que você possa considerar a jaguatirica como um gateway de API simples, capaz e leve, adequado para cenários de nível de produção. Além disso, a versão mais recente do Ocelot contém uma alteração de quebra em seu esquema json. Considere usar Ocelot < v16.0.0 ou use as principais Rotas em vez de ReRoutes.

Arquitete e projete seus gateways de API

O diagrama de arquitetura a seguir mostra como os API Gateways foram implementados com Ocelot no eShopOnContainers.

Diagram showing the eShopOnContainers architecture.

Figura 6-28. Arquitetura eShopOnContainers com API Gateways

Esse diagrama mostra como todo o aplicativo é implantado em um único host Docker ou PC de desenvolvimento com "Docker para Windows" ou "Docker para Mac". No entanto, a implantação em qualquer orquestrador seria semelhante, mas qualquer contêiner no diagrama poderia ser dimensionado no orquestrador.

Além disso, os ativos de infraestrutura, como bancos de dados, cache e agentes de mensagens, devem ser descarregados do orquestrador e implantados em sistemas altamente disponíveis para infraestrutura, como o Banco de Dados SQL do Azure, o Azure Cosmos DB, o Azure Redis, o Barramento de Serviço do Azure ou qualquer solução de cluster de HA local.

Como você também pode notar no diagrama, ter vários Gateways de API permite que várias equipes de desenvolvimento sejam autônomas (neste caso, recursos de Marketing versus recursos de Compras) ao desenvolver e implantar seus microsserviços, além de seus próprios Gateways de API relacionados.

Se você tivesse um único API Gateway monolítico, isso significaria um único ponto a ser atualizado por várias equipes de desenvolvimento, o que poderia acoplar todos os microsserviços com uma única parte do aplicativo.

Indo muito mais longe no design, às vezes um API Gateway refinado também pode ser limitado a um único microsserviço de negócios, dependendo da arquitetura escolhida. Ter os limites do API Gateway ditados pela empresa ou domínio irá ajudá-lo a obter um design melhor.

Por exemplo, a granularidade fina na camada do API Gateway pode ser especialmente útil para aplicativos de interface do usuário compostos mais avançados baseados em microsserviços, porque o conceito de um API Gateway refinado é semelhante a um serviço de composição de interface do usuário.

Mergulhamos em mais detalhes na seção anterior Criando interface do usuário composta com base em microsserviços.

Como uma conclusão importante, para muitos aplicativos de médio e grande porte, usar um produto de API Gateway personalizado geralmente é uma boa abordagem, mas não como um único agregador monolítico ou um gateway de API personalizado central exclusivo, a menos que esse API Gateway permita várias áreas de configuração independentes para as várias equipes de desenvolvimento que criam microsserviços autônomos.

Exemplos de microsserviços/contêineres para redirecionar através dos Gateways de API

Como exemplo, eShopOnContainers tem cerca de seis tipos de microsserviços internos que precisam ser publicados por meio dos API Gateways, conforme mostrado na imagem a seguir.

Screenshot of the Services folder showing its subfolders.

Figura 6-29. Pastas de microsserviço na solução eShopOnContainers no Visual Studio

Sobre o serviço Identity, no design ele é deixado de fora do roteamento do API Gateway porque é a única preocupação transversal no sistema, embora com Ocelot também seja possível incluí-lo como parte das listas de reencaminhamento.

Todos esses serviços são atualmente implementados como ASP.NET serviços de API Web principal, como você pode ver pelo código. Vamos nos concentrar em um dos microsserviços, como o código de microsserviço do catálogo.

Screenshot of Solution Explorer showing Catalog.API project contents.

Figura 6-30. Exemplo de microsserviço de API da Web (microsserviço de catálogo)

Você pode ver que o microsserviço de catálogo é um projeto típico de API Web ASP.NET Core com vários controladores e métodos, como no código a seguir.

[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();
}

A solicitação HTTP acabará executando esse tipo de código C#, acessando o banco de dados de microsserviço e qualquer ação adicional necessária.

Em relação à URL do microsserviço, quando os contêineres são implantados em seu PC de desenvolvimento local (host Docker local), o contêiner de cada microsserviço sempre tem uma porta interna (geralmente porta 80) especificada em seu dockerfile, como no seguinte dockerfile:

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

A porta 80 mostrada no código é interna dentro do host do Docker, portanto, não pode ser acessada por aplicativos cliente.

Os aplicativos cliente podem acessar somente as portas externas (se houver) publicadas durante a implantação com docker-composeo .

Essas portas externas não devem ser publicadas ao implantar em um ambiente de produção. Por esse motivo específico, por que você deseja usar o API Gateway, para evitar a comunicação direta entre os aplicativos cliente e os microsserviços.

No entanto, ao desenvolver, você deseja acessar o microsserviço/contêiner diretamente e executá-lo através do Swagger. É por isso que no eShopOnContainers, as portas externas ainda são especificadas mesmo quando não serão usadas pelo API Gateway ou pelos aplicativos cliente.

Aqui está um exemplo do docker-compose.override.yml arquivo para o microsserviço de catálogo:

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).

Você pode ver como na configuração docker-compose.override.yml a porta interna para o contêiner Catálogo é a porta 80, mas a porta para acesso externo é 5101. Mas essa porta não deve ser usada pelo aplicativo ao usar um API Gateway, apenas para depurar, executar e testar apenas o microsserviço do Catálogo.

Normalmente, você não implantará com docker-compose em um ambiente de produção porque o ambiente de implantação de produção certo para microsserviços é um orquestrador como o Kubernetes ou o Service Fabric. Ao implantar nesses ambientes, você usa arquivos de configuração diferentes, nos quais não publicará diretamente nenhuma porta externa para os microsserviços, mas sempre usará o proxy reverso do API Gateway.

Execute o microsserviço de catálogo em seu host Docker local. Execute a solução completa eShopOnContainers a partir do Visual Studio (ele executa todos os serviços nos arquivos docker-compose) ou inicie o microsserviço Catalog com o seguinte comando docker-compose no CMD ou PowerShell posicionado na pasta onde o docker-compose.yml e docker-compose.override.yml são colocados.

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

Este comando executa apenas o contêiner de serviço catalog-api mais as dependências especificadas no docker-compose.yml. Nesse caso, o contêiner SQL Server e o contêiner RabbitMQ.

Em seguida, você pode acessar diretamente o microsserviço do catálogo e ver seus métodos através da interface do usuário do Swagger acessando diretamente através dessa porta "externa", neste caso http://host.docker.internal:5101/swagger:

Screenshot of Swagger UI showing the Catalog.API REST API.

Figura 6-31. Testando o microsserviço do catálogo com sua interface do usuário do Swagger

Neste ponto, você pode definir um ponto de interrupção no código C# no Visual Studio, testar o microsserviço com os métodos expostos na interface do usuário do Swagger e, finalmente, limpar tudo com o docker-compose down comando.

No entanto, a comunicação de acesso direto ao microsserviço, neste caso através da porta externa 5101, é precisamente o que pretende evitar na sua aplicação. E você pode evitar isso definindo o nível adicional de indirecionamento do API Gateway (Ocelot, neste caso). Dessa forma, o aplicativo cliente não acessará diretamente o microsserviço.

Implementando seus gateways de API com Ocelot

Ocelot é basicamente um conjunto de middleware que você pode aplicar em uma ordem específica.

A jaguatirica foi projetada para funcionar apenas com ASP.NET Core. A versão mais recente do pacote é 18.0 que tem como alvo o .NET 6 e, portanto, não é adequado para aplicativos .NET Framework.

Você instala o Ocelot e suas dependências em seu projeto ASP.NET Core com o pacote NuGet do Ocelot, do Visual Studio.

Install-Package Ocelot

No eShopOnContainers, sua implementação do API Gateway é um projeto WebHost ASP.NET Core simples, e o middleware da Ocelot lida com todos os recursos do API Gateway, conforme mostrado na imagem a seguir:

Screenshot of Solution Explorer showing Ocelot API gateway project.

Figura 6-32. O projeto base OcelotApiGw em eShopOnContainers

Este ASP.NET projeto Core WebHost é construído com dois arquivos simples: Program.cs e Startup.cs.

O Program.cs só precisa criar e configurar o típico 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;
        }
    }
}

O ponto importante aqui para Ocelot é o configuration.json arquivo que você deve fornecer ao construtor através do AddJsonFile() método. É aí que configuration.json você especifica todos os ReRoutes do API Gateway, ou seja, os pontos de extremidade externos com portas específicas e os pontos de extremidade internos correlacionados, geralmente usando portas diferentes.

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

Há duas seções para a configuração. Uma matriz de ReRoutes e uma GlobalConfiguration. Os ReRoutes são os objetos que dizem a Ocelot como tratar uma solicitação a montante. A configuração Global permite substituições de configurações específicas do ReRoute. É útil se você não quiser gerenciar muitas configurações específicas do ReRoute.

Aqui está um exemplo simplificado do arquivo de configuração ReRoute de um dos API Gateways do 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"
    }
  }

A principal funcionalidade de um Ocelot API Gateway é receber solicitações HTTP recebidas e encaminhá-las para um serviço downstream, atualmente como outra solicitação HTTP. Ocelot's descreve o roteamento de uma solicitação para outra como um ReRoute.

Por exemplo, vamos nos concentrar em um dos ReRoutes no configuration.json acima, a configuração para o microsserviço 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": []
      }
}

O DownstreamPathTemplate, Scheme e DownstreamHostAndPorts fazem a URL interna do microsserviço para a qual essa solicitação será encaminhada.

A porta é a porta interna usada pelo serviço. Ao usar contêineres, a porta especificada em seu dockerfile.

O Host é um nome de serviço que depende da resolução de nome de serviço que você está usando. Ao usar docker-compose, os nomes de serviços são fornecidos pelo Docker Host, que está usando os nomes de serviço fornecidos nos arquivos docker-compose. Se estiver usando um orquestrador como o Kubernetes ou o Service Fabric, esse nome deve ser resolvido pelo DNS ou pela resolução de nomes fornecida por cada orquestrador.

DownstreamHostAndPorts é uma matriz que contém o host e a porta de quaisquer serviços downstream para os quais você deseja encaminhar solicitações. Normalmente, essa configuração conterá apenas uma entrada, mas às vezes você pode querer balancear a carga de solicitações para seus serviços downstream e Ocelot permite adicionar mais de uma entrada e, em seguida, selecionar um balanceador de carga. Mas se estiver usando o Azure e qualquer orquestrador, provavelmente é uma ideia melhor balancear a carga com a infraestrutura de nuvem e orquestrador.

O UpstreamPathTemplate é a URL que Ocelot usará para identificar qual DownstreamPathTemplate usar para uma determinada solicitação do cliente. Finalmente, o UpstreamHttpMethod é usado para que Ocelot possa distinguir entre diferentes solicitações (GET, POST, PUT) para a mesma URL.

Neste ponto, você pode ter um único Ocelot API Gateway (ASP.NET Core WebHost) usando um ou vários arquivos configuration.json mesclados ou você também pode armazenar a configuração em uma loja Consul KV.

Mas, conforme introduzido nas seções de arquitetura e design, se você realmente quiser ter microsserviços autônomos, talvez seja melhor dividir esse único API Gateway monolítico em vários API Gateways e/ou BFF (Backend for Frontend). Para isso, vamos ver como implementar essa abordagem com contêineres do Docker.

Usando uma única imagem de contêiner do Docker para executar vários tipos diferentes de contêiner API Gateway/BFF

No eShopOnContainers, estamos usando uma única imagem de contêiner do Docker com o Ocelot API Gateway, mas depois, em tempo de execução, criamos serviços/contêineres diferentes para cada tipo de API-Gateway/BFF fornecendo um arquivo configuration.json diferente, usando um volume docker para acessar uma pasta de PC diferente para cada serviço.

Diagram of a single Ocelot gateway Docker image for all API gateways.

Figura 6-33. Reutilizando uma única imagem do Ocelot Docker em vários tipos de API Gateway

Em eShopOnContainers, a "Imagem Genérica do Docker do Ocelot API Gateway" é criada com o projeto chamado 'OcelotApiGw' e o nome da imagem 'eshop/ocelotapigw' especificado no arquivo docker-compose.yml. Em seguida, ao implantar no Docker, haverá quatro contêineres API-Gateway criados a partir dessa mesma imagem do Docker, conforme mostrado na seguinte extração do arquivo 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

Além disso, como você pode ver no arquivo de docker-compose.override.yml a seguir, a única diferença entre esses contêineres do API Gateway é o arquivo de configuração Ocelot, que é diferente para cada contêiner de serviço e é especificado em tempo de execução por meio de um volume do 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

Devido a esse código anterior, e conforme mostrado no Visual Studio Explorer abaixo, o único arquivo necessário para definir cada Business / BFF API Gateway específico é apenas um arquivo configuration.json, porque os quatro API Gateways são baseados na mesma imagem do Docker.

Screenshot showing all API gateways with configuration.json files.

Figura 6-34. O único arquivo necessário para definir cada API Gateway / BFF com Ocelot é um arquivo de configuração

Ao dividir o API Gateway em vários API Gateways, diferentes equipes de desenvolvimento com foco em diferentes subconjuntos de microsserviços podem gerenciar seus próprios API Gateways usando arquivos de configuração Ocelot independentes. Além disso, ao mesmo tempo, eles podem reutilizar a mesma imagem do Ocelot Docker.

Agora, se você executar eShopOnContainers com os API Gateways (incluídos por padrão no VS ao abrir eShopOnContainers-ServicesAndWebApps.sln solução ou se estiver executando "docker-compose up"), as seguintes rotas de exemplo serão executadas.

Por exemplo, ao visitar a URL http://host.docker.internal:5202/api/v1/c/catalog/items/2/ upstream servida pelo webshoppingapigw API Gateway, você obtém o mesmo resultado da URL http://catalog-api/api/v1/2 Downstream interna dentro do host Docker, como no navegador a seguir.

Screenshot of a browser showing a response going through API gateway.

Figura 6-35. Acessando um microsserviço por meio de uma URL fornecida pelo API Gateway

Por motivos de teste ou depuração, se você quiser acessar diretamente o contêiner do Catalog Docker (somente no ambiente de desenvolvimento) sem passar pelo API Gateway, já que 'catalog-api' é uma resolução DNS interna ao host do Docker (descoberta de serviço manipulada por nomes de serviço docker-compose), a única maneira de acessar diretamente o contêiner é através da porta externa publicada no docker-compose.override.yml, que é fornecido apenas para testes de desenvolvimento, como http://host.docker.internal:5101/api/v1/Catalog/items/1 no navegador a seguir.

Screenshot of a browser showing a direct response to the Catalog.api.

Figura 6-36. Acesso direto a um microsserviço para fins de teste

Mas o aplicativo é configurado para que ele acesse todos os microsserviços através dos API Gateways, não através dos "atalhos" de porta direta.

O padrão de agregação de gateway no eShopOnContainers

Como introduzido anteriormente, uma maneira flexível de implementar a agregação de solicitações é com serviços personalizados, por código. Você também pode implementar a agregação de solicitações com o recurso de agregação de solicitações no Ocelot, mas ela pode não ser tão flexível quanto você precisa. Portanto, a maneira selecionada de implementar a agregação no eShopOnContainers é com um serviço explícito ASP.NET Core Web API para cada agregador.

De acordo com essa abordagem, o diagrama de composição do API Gateway é, na realidade, um pouco mais extenso ao considerar os serviços agregadores que não são mostrados no diagrama de arquitetura global simplificado mostrado anteriormente.

No diagrama a seguir, você também pode ver como os serviços agregadores funcionam com seus gateways de API relacionados.

Diagram of eShopOnContainers architecture showing aggregator services.

Figura 6-37. Arquitetura eShopOnContainers com serviços agregadores

Ampliando ainda mais, na área de negócios "Compras" na imagem a seguir, você pode ver que a conversação entre os aplicativos cliente e os microsserviços é reduzida ao usar os serviços agregadores nos Gateways de API.

Diagram showing eShopOnContainers architecture zoom in.

Figura 6-38. Visão ampliada dos serviços do Agregador

Você pode notar como quando o diagrama mostra as possíveis solicitações provenientes dos Gateways de API, ele pode ficar complexo. Por outro lado, quando você usa o padrão agregador, você pode ver como as setas em azul simplificariam a comunicação de uma perspetiva de aplicativo cliente. Esse padrão não só ajuda a reduzir a tagarelice e a latência na comunicação, mas também melhora significativamente a experiência do usuário para os aplicativos remotos (aplicativos móveis e SPA).

No caso da área de negócio "Marketing" e microsserviços, trata-se de um caso de uso simples, pelo que não houve necessidade de utilizar agregadores, mas também poderia ser possível, se necessário.

Autenticação e autorização em Ocelot API Gateways

Em um Ocelot API Gateway, você pode sentar o serviço de autenticação, como um serviço de API Web ASP.NET Core usando o IdentityServer fornecendo o token de autenticação, fora ou dentro do API Gateway.

Como o eShopOnContainers está usando vários Gateways de API com limites baseados em BFF e áreas de negócios, o serviço de Identidade/Autenticação é deixado de fora dos Gateways de API, conforme destacado em amarelo no diagrama a seguir.

Diagram showing Identity microservice beneath the API gateway.

Figura 6-39. Posição do serviço de Identidade no eShopOnContainers

No entanto, Ocelot também suporta colocar o microsserviço Identity/Auth dentro do limite do API Gateway, como neste outro diagrama.

Diagram showing authentication in an Ocelot API Gateway.

Figura 6-40. Autenticação em jaguatirica

Como mostra o diagrama anterior, quando o microsserviço de identidade está abaixo do gateway de API (AG): 1) AG solicita um token de autenticação do microsserviço de identidade, 2) O microsserviço de identidade retorna token para AG, 3-4) solicitações AG de microsserviços usando o token de autenticação. Como o aplicativo eShopOnContainers dividiu o API Gateway em vários BFF (Backend for Frontend) e Gateways de API de áreas de negócios, outra opção teria sido criar um API Gateway adicional para preocupações transversais. Essa escolha seria justa em uma arquitetura baseada em microsserviços mais complexa, com vários microsserviços transversais. Como há apenas uma preocupação transversal no eShopOnContainers, foi decidido lidar apenas com o serviço de segurança fora do domínio do API Gateway, por uma questão de simplicidade.

Em qualquer caso, se o aplicativo estiver protegido no nível do API Gateway, o módulo de autenticação do Ocelot API Gateway será visitado primeiro ao tentar usar qualquer microsserviço seguro. Isso redireciona a solicitação HTTP para visitar o microsserviço de identidade ou autenticação para obter o token de acesso para que você possa visitar os serviços protegidos com o access_token.

A maneira de proteger com autenticação qualquer serviço no nível do API Gateway é definindo o AuthenticationProviderKey em suas configurações relacionadas no configuration.json.

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

Quando o Ocelot for executado, ele examinará o ReRoutes AuthenticationOptions.AuthenticationProviderKey e verificará se há um Provedor de Autenticação registrado com a chave fornecida. Se não houver, a jaguatirica não arrancará. Se houver, o ReRoute usará esse provedor quando for executado.

Como o Ocelot WebHost está configurado com o authenticationProviderKey = "IdentityApiKey", isso exigirá autenticação sempre que esse serviço tiver quaisquer solicitações sem qualquer token de autenticação.

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" }
                    };
                });
            //...
        }
    }
}

Em seguida, você também precisa definir a autorização com o atributo [Autorizar] em qualquer recurso a ser acessado como os microsserviços, como no seguinte controlador de microsserviço Basket.

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

Os ValidAudiences, como "basket", estão correlacionados com o público definido em cada microsserviço com AddJwtBearer() o ConfigureServices() da classe Startup, como no código abaixo.

// 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 você tentar acessar qualquer microsserviço seguro, como o microsserviço Basket com uma URL ReRoute baseada no API Gateway como http://host.docker.internal:5202/api/v1/b/basket/1, você receberá um 401 Não Autorizado, a menos que forneça um token válido. Por outro lado, se uma URL de ReRoute for autenticada, a Ocelot invocará qualquer esquema downstream associado a ela (a URL de microsserviço interna).

Autorização no nível ReRoutes da Ocelot. Ocelot suporta autorização baseada em declarações avaliada após a autenticação. Você define a autorização em um nível de rota adicionando as seguintes linhas à configuração ReRoute.

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

Nesse exemplo, quando o middleware de autorização é chamado, Ocelot descobrirá se o usuário tem o tipo de declaração 'UserType' no token e se o valor dessa declaração é 'employee'. Se não for, então o usuário não será autorizado e a resposta será 403 proibida.

Usando Kubernetes Ingress e Ocelot API Gateways

Ao usar o Kubernetes (como em um cluster do Serviço Kubernetes do Azure), você geralmente unifica todas as solicitações HTTP por meio da camada de Ingresso do Kubernetes baseada no Nginx.

No Kubernetes, se você não usar nenhuma abordagem de entrada, seus serviços e pods terão IPs roteáveis apenas pela rede de cluster.

Mas se você usar uma abordagem de entrada, terá uma camada intermediária entre a Internet e seus serviços (incluindo seus gateways de API), agindo como um proxy reverso.

Como definição, um Ingress é uma coleção de regras que permitem que as conexões de entrada alcancem os serviços de cluster. Uma entrada é configurada para fornecer serviços de URLs acessíveis externamente, tráfego de balanceamento de carga, terminação SSL e muito mais. Os usuários solicitam a entrada por POSTing do recurso Ingress no servidor de API.

No eShopOnContainers, ao desenvolver localmente e usar apenas sua máquina de desenvolvimento como host do Docker, você não está usando nenhuma entrada, mas apenas os vários gateways de API.

No entanto, ao direcionar um ambiente de "produção" baseado no Kubernetes, o eShopOnContainers está usando uma entrada na frente dos gateways de API. Dessa forma, os clientes ainda chamam a mesma URL base, mas as solicitações são roteadas para vários API Gateways ou BFF.

API Gateways são front-ends ou fachadas que apresentam apenas os serviços, mas não os aplicativos Web que geralmente estão fora de seu escopo. Além disso, os Gateways de API podem ocultar determinados microsserviços internos.

A entrada, no entanto, é apenas redirecionando solicitações HTTP, mas não tentando ocultar qualquer microsserviço ou aplicativo web.

Ter uma camada Nginx de entrada no Kubernetes na frente das aplicações web mais os vários Ocelot API Gateways / BFF é a arquitetura ideal, como mostrado no diagrama a seguir.

A diagram showing how an ingress tier fits into the AKS environment.

Figura 6-41. A camada de entrada no eShopOnContainers quando implantada no Kubernetes

Um Kubernetes Ingress atua como um proxy reverso para todo o tráfego para o aplicativo, incluindo os aplicativos Web, que estão fora do escopo do gateway de API. Quando você implanta o eShopOnContainers no Kubernetes, ele expõe apenas alguns serviços ou endpoints via ingresso, basicamente a seguinte lista de postfixes nas URLs:

  • / para a aplicação Web SPA cliente
  • /webmvc para o aplicativo Web MVC cliente
  • /webstatus para o aplicativo Web cliente mostrando o status/verificações de integridade
  • /webshoppingapigw para o BFF web e processos de negócios de compras
  • /webmarketingapigw para o BFF web e processos de negócios de marketing
  • /mobileshoppingapigw para o BFF móvel e processos de negócios de compras
  • /mobilemarketingapigw para o BFF móvel e processos de negócios de marketing

Ao implantar no Kubernetes, cada Ocelot API Gateway está usando um arquivo "configuration.json" diferente para cada pod que executa os API Gateways. Esses arquivos "configuration.json" são fornecidos pela montagem (originalmente com o script deploy.ps1) de um volume criado com base em um mapa de configuração do Kubernetes chamado 'jaguatirica'. Cada contêiner monta seu arquivo de configuração relacionado na pasta do contêiner chamada /app/configuration.

Nos arquivos de código-fonte do eShopOnContainers, os arquivos "configuration.json" originais podem ser encontrados dentro da k8s/ocelot/ pasta. Há um arquivo para cada BFF/APIGateway.

Recursos transversais adicionais em um Ocelot API Gateway

Existem outros recursos importantes para pesquisar e usar, ao usar um Ocelot API Gateway, descritos nos links a seguir.