Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Dica
Esse conteúdo é um trecho do eBook, arquitetura de microsserviços do .NET para aplicativos .NET em contêineres, disponível em do .NET Docs ou como um PDF para download gratuito que pode ser lido offline.
Importante
O aplicativo de microsserviço de referência eShopOnContainers está usando recursos fornecidos pelo Envoy para implementar o Gateway de API em vez do Ocelot referenciado anteriormente. Fizemos essa escolha de design devido ao suporte interno do Envoy para o protocolo WebSocket, exigido pelas novas comunicações entre serviços gRPC implementadas no eShopOnContainers. No entanto, mantivemos esta seção no guia para que você possa considerar o Ocelot 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 significativa em seu esquema json. Considere usar o Ocelot < v16.0.0 ou usar as principais Rotas em vez de ReRoutes.
Arquitetar e projetar seus Gateways de API
O diagrama de arquitetura a seguir mostra como os Gateways de API foram implementados com o Ocelot no eShopOnContainers.
Figura 6-28. Arquitetura do eShopOnContainers com Gateways de API
Esse diagrama mostra como todo o aplicativo é implantado em um único host do Docker ou computador de desenvolvimento com "Docker for Windows" ou "Docker for 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 de alta disponibilidade para infraestrutura, como Banco de Dados SQL do Azure, Azure Cosmos DB, Redis do Azure, Barramento de Serviço do Azure ou qualquer solução de clustering de HA local.
Como você também pode observar no diagrama, ter vários Gateways de API permite que várias equipes de desenvolvimento sejam autônomas (nesse 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 Gateway de API monolítico que significaria um único ponto a ser atualizado por várias equipes de desenvolvimento, o que poderia associar todos os microsserviços com uma única parte do aplicativo.
Indo muito mais longe no design, às vezes um Gateway de API refinado também pode ser limitado a um único microsserviço de negócios, dependendo da arquitetura escolhida. Ter os limites do Gateway de API ditados pela empresa ou pelo domínio ajudará você a obter um design melhor.
Por exemplo, a granularidade fina na camada de Gateway de API pode ser especialmente útil para aplicativos de interface do usuário compostos mais avançados que se baseiam em microsserviços, pois o conceito de um Gateway de API refinado é semelhante a um serviço de composição de interface do usuário.
Nos aprofundamos em mais detalhes na seção anterior Criando interface do usuário composta com base em microsserviços.
Como uma abordagem importante, para muitos aplicativos de médio e grande porte, usar um produto de Gateway de API personalizado geralmente é uma boa abordagem, mas não como um único agregador monolítico ou gateway de API personalizado central exclusivo, a menos que o Gateway de API permita várias áreas de configuração independentes para as várias equipes de desenvolvimento criando microsserviços autônomos.
Microsserviços/contêineres de exemplo para redirecionar por meio dos Gateways de API
Por exemplo, o eShopOnContainers tem cerca de seis tipos de microsserviço internos que precisam ser publicados por meio dos Gateways de API, conforme mostrado na imagem a seguir.
Figura 6-29. Pastas de microsserviço na solução eShopOnContainers no Visual Studio
Sobre o serviço identidade, no design, ele fica de fora do roteamento do Gateway de API porque é a única preocupação entre cortes no sistema, embora com o Ocelot também seja possível incluí-lo como parte das listas de redirecionamento.
Todos esses serviços estão atualmente implementados como ASP.NET Principais serviços de API Web, como você pode dizer no código. Vamos nos concentrar em um dos microsserviços, como o código de microsserviço catálogo.
Figura 6-30. Microsserviço de API Web de exemplo (microsserviço de catálogo)
Você pode ver que o microsserviço de catálogo é um projeto típico de API Web do 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 de microsserviço, quando os contêineres são implantados no computador de desenvolvimento local (host local do Docker), cada contêiner de microsserviço sempre tem uma porta interna (geralmente a 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, ela não pode ser acessada por aplicativos cliente.
Os aplicativos cliente podem acessar apenas as portas externas (se houver) publicadas ao implantar com docker-compose.
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 Gateway de API, 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 por meio do Swagger. É por isso que, no eShopOnContainers, as portas externas ainda são especificadas mesmo quando não serão usadas pelo Gateway de API ou pelos aplicativos cliente.
Aqui está um exemplo do docker-compose.override.yml arquivo para o microsserviço 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 de docker-compose.override.yml, a porta interna do 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 Gateway de API, apenas para depurar, executar e testar apenas o microsserviço catálogo.
Normalmente, você não será implantado com docker-compose em um ambiente de produção porque o ambiente de implantação de produção correto para microsserviços é um orquestrador como o Kubernetes ou o Service Fabric. Ao implantar nesses ambientes, você usa arquivos de configuração diferentes em que não publicará diretamente nenhuma porta externa para os microsserviços, mas sempre usará o proxy reverso do Gateway de API.
Execute o microsserviço de catálogo no host local do Docker. Execute a solução completa eShopOnContainers do Visual Studio (ele executa todos os serviços nos arquivos docker-compose) ou inicie o microsserviço catálogo com o seguinte comando docker-compose no CMD ou powerShell posicionado na pasta em que o docker-compose.yml e docker-compose.override.yml são colocados.
docker-compose run --service-ports catalog-api
Esse comando executa apenas o contêiner de serviço de api de catálogo mais as dependências especificadas no docker-compose.yml. Nesse caso, o contêiner do SQL Server e o contêiner RabbitMQ.
Em seguida, você pode acessar diretamente o microsserviço catálogo e ver seus métodos por meio da interface do usuário do Swagger acessando diretamente por meio dessa porta "externa", nesse caso http://host.docker.internal:5101/swagger:
Figura 6-31. Testando o microsserviço de 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, por fim, limpar tudo com o docker-compose down comando.
No entanto, a comunicação de acesso direto ao microsserviço, nesse caso por meio da porta externa 5101, é precisamente o que você deseja evitar em seu aplicativo. E você pode evitar isso definindo o nível adicional de indireção do Gateway de API (Ocelot, nesse caso). Dessa forma, o aplicativo cliente não acessará diretamente o microsserviço.
Implementando seus Gateways de API com o Ocelot
O Ocelot é basicamente um conjunto de middleware que você pode aplicar em uma ordem específica.
O Ocelot foi projetado para trabalhar apenas com ASP.NET Core. A versão mais recente do pacote é a 18.0, que tem como destino o .NET 6 e, portanto, não é adequada para aplicativos do .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 de Gateway de API é um projeto ASP.NET Core WebHost simples e o middleware do Ocelot manipula todos os recursos do Gateway de API, conforme mostrado na imagem a seguir:
Figura 6-32. O projeto base OcelotApiGw em eShopOnContainers
Este projeto ASP.NET Core WebHost é criado com dois arquivos simples: Program.cs e Startup.cs.
O Program.cs só precisa criar e configurar o buildWebHost ASP.NET core típico.
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 o Ocelot é o configuration.json arquivo que você deve fornecer ao construtor por meio do AddJsonFile() método. É aí que configuration.json você especifica todos os ReRoutes do Gateway de API, 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 um GlobalConfiguration. Os ReRoutes são os objetos que dizem a Ocelot como tratar uma solicitação upstream. 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 Gateways de API 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 Gateway de API do Ocelot é fazer solicitações HTTP de entrada e encaminhá-las para um serviço downstream, atualmente como outra solicitação HTTP. O Ocelot 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 do 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 tornam a URL de microsserviço interna 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.
É Host um nome de serviço que depende da resolução de nomes de serviço que você está usando. Ao usar docker-compose, os nomes dos serviços são fornecidos pelo Host do Docker, que está usando os nomes de serviço fornecidos nos arquivos docker-compose. Se estiver usando um orquestrador como Kubernetes ou Service Fabric, esse nome deverá 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 todos os serviços downstream para os quais você deseja encaminhar solicitações. Normalmente, essa configuração conterá apenas uma entrada, mas, às vezes, talvez você queira balancear a carga de solicitações para seus serviços downstream e o Ocelot permite adicionar mais de uma entrada e, em seguida, selecionar um balanceador de carga. No entanto, 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 o Ocelot usará para identificar qual DownstreamPathTemplate usar para uma determinada solicitação do cliente. Por fim, o UpstreamHttpMethod é usado para que Ocelot possa distinguir entre solicitações diferentes (GET, POST, PUT) para a mesma URL.
Neste ponto, você pode ter um único Gateway de API Ocelot (ASP.NET Core WebHost) usando um ou vários arquivos de configuration.json mesclados ou também pode armazenar a configuração em um repositório Cônsul 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 gateway de API monolítico único em vários Gateways de API e/ou BFF (Back-end para Front-end). Para essa finalidade, 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 de contêiner de Gateway de API/BFF diferentes
No eShopOnContainers, estamos usando uma única imagem de contêiner do Docker com o Gateway de API do Ocelot, mas, em tempo de execução, criamos serviços/contêineres diferentes para cada tipo de API-Gateway/BFF fornecendo um arquivo de configuration.json diferente, usando um volume do Docker para acessar uma pasta de COMPUTADOR diferente para cada serviço.
Figura 6-33. Reutilizando uma única imagem do Docker do Ocelot em vários tipos de Gateway de API
No eShopOnContainers, a "Imagem do Docker do Gateway de API do Ocelot Genérico" é 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 extração a seguir 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 de Gateway de API é 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 Gerenciador do Visual Studio abaixo, o único arquivo necessário para definir cada Gateway de API comercial/BFF específico é apenas um arquivo configuration.json, pois os quatro Gateways de API são baseados na mesma imagem do Docker.
Figura 6-34. O único arquivo necessário para definir cada Gateway de API/BFF com Ocelot é um arquivo de configuração
Dividindo o Gateway de API em vários Gateways de API, diferentes equipes de desenvolvimento com foco em diferentes subconjuntos de microsserviços podem gerenciar seus próprios Gateways de API usando arquivos de configuração independentes do Ocelot. Além disso, ao mesmo tempo, eles podem reutilizar a mesma imagem do Docker Ocelot.
Agora, se você executar eShopOnContainers com os Gateways de API (incluídos por padrão no VS ao abrir eShopOnContainers-ServicesAndWebApps.sln solução ou se estiver executando "docker-compose up"), as rotas de exemplo a seguir serão executadas.
Por exemplo, ao visitar a URL http://host.docker.internal:5202/api/v1/c/catalog/items/2/ upstream atendida pelo Gateway de API webshoppingapigw, você obtém o mesmo resultado da URL http://catalog-api/api/v1/2 downstream interna no host do Docker, como no navegador a seguir.
Figura 6-35. Acessando um microsserviço por meio de uma URL fornecida pelo Gateway de API
Devido a motivos de teste ou depuração, se você quiser acessar diretamente o contêiner do Docker do Catálogo (somente no ambiente de desenvolvimento) sem passar pelo Gateway de API, já que 'catalog-api' é uma resolução DNS interna para o host do Docker (descoberta de serviço manipulada por nomes de serviço docker-compose), a única maneira de acessar diretamente o contêiner é por meio 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.
Figura 6-36. Acesso direto a um microsserviço para fins de teste
Mas o aplicativo está configurado para acessar todos os microsserviços por meio dos Gateways de API, não por meio dos "atalhos" da porta direta.
O padrão de agregação do Gateway em eShopOnContainers
Conforme introduzido anteriormente, uma maneira flexível de implementar a agregação de solicitações é com serviços personalizados, por código. A maneira selecionada de implementar a agregação no eShopOnContainers é com um serviço de API Web ASP.NET Core explícito para cada agregador.
De acordo com essa abordagem, o diagrama de composição do Gateway de API é, na realidade, um pouco mais estendido ao considerar os serviços de agregador 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 de agregador funcionam com seus Gateways de API relacionados.
Figura 6-37. Arquitetura eShopOnContainers com serviços de agregador
Ampliando ainda mais a área de negócios "Compras" na imagem a seguir, você pode ver que a conversa entre os aplicativos cliente e os microsserviços é reduzida ao usar os serviços de agregador nos Gateways de API.
Figura 6-38. Ampliar a visão dos serviços do Agregador
Você pode observar como quando o diagrama mostra as possíveis solicitações provenientes dos Gateways de API, ele pode ficar complexo. Por outro lado, ao usar o padrão agregador, você pode ver como as setas em azul simplificariam a comunicação de uma perspectiva do aplicativo cliente. Esse padrão não só ajuda a reduzir a conversa e a latência na comunicação, como 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ócios e microsserviços de "Marketing", é um caso de uso simples, portanto, não havia necessidade de usar agregadores, mas também poderia ser possível, se necessário.
Autenticação e autorização em Gateways de API do Ocelot
Em um Gateway de API Ocelot, 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 Gateway de API.
Como o eShopOnContainers está usando vários Gateways de API com limites baseados em BFF e áreas de negócios, o serviço identidade/autenticação é deixado de fora dos Gateways de API, conforme realçado em amarelo no diagrama a seguir.
Figura 6-39. Posição do serviço identidade em eShopOnContainers
No entanto, o Ocelot também dá suporte ao microsserviço identidade/autenticação dentro do limite do Gateway de API, como neste outro diagrama.
Figura 6-40. Autenticação no Ocelot
Como mostra o diagrama anterior, quando o microsserviço identity está abaixo do AG (gateway de API): 1) o AG solicita um token de autenticação do microsserviço de identidade, 2) O microsserviço de identidade retorna token para solicitações ag, 3-4) AG de microsserviços usando o token de autenticação. Como o aplicativo eShopOnContainers dividiu o Gateway de API em vários Gateways de API de BFF (Back-end para Frontend) e de áreas de negócios, outra opção teria sido criar um Gateway de API adicional para preocupações de corte cruzado. Essa escolha seria justa em uma arquitetura baseada em microsserviço mais complexa, com vários microsserviços de questões de corte cruzado. Como há apenas uma preocupação cruzada no eShopOnContainers, foi decidido apenas lidar com o serviço de segurança fora do reino do Gateway de API, para simplificar.
De qualquer forma, se o aplicativo for protegido no nível do Gateway de API, o módulo de autenticação do Gateway de API do Ocelot será visitado inicialmente ao tentar usar qualquer microsserviço protegido. Isso redireciona a solicitação HTTP para visitar a Identidade ou o microsserviço de autenticação para obter o token de acesso para que você possa visitar os serviços protegidos com o access_token.
A maneira como você protege com a autenticação qualquer serviço no nível do Gateway de API é definindo a 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, o Ocelot não iniciará. Se houver, o ReRoute usará esse provedor quando ele for executado.
Como o Ocelot WebHost está configurado com o authenticationProviderKey = "IdentityApiKey", isso exigirá autenticação sempre que esse serviço tiver solicitações sem nenhum 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 [Authorize] em qualquer recurso a ser acessado como os microsserviços, como no controlador de microsserviço Basket a seguir.
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{
[Route("api/v1/[controller]")]
[Authorize]
public class BasketController : Controller
{
//...
}
}
As ValidAudiences, como "basket", são correlacionadas com o público definido em cada microsserviço com AddJwtBearer() a classe 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 de ReRoute com base no Gateway de API, http://host.docker.internal:5202/api/v1/b/basket/1você obterá um 401 Não autorizado, a menos que forneça um token válido. Por outro lado, se uma URL do ReRoute for autenticada, o Ocelot invocará qualquer esquema downstream associado a ele (a URL de microsserviço interno).
Autorização na camada ReRoutes do Ocelot. O Ocelot dá suporte à autorização baseada em declarações avaliada após a autenticação. Defina a autorização em um nível de rota adicionando as linhas a seguir à configuração do ReRoute.
"RouteClaimsRequirement": {
"UserType": "employee"
}
Nesse exemplo, quando o middleware de autorização é chamado, o Ocelot descobrirá se o usuário tem o tipo de declaração 'UserType' no token e se o valor dessa declaração é 'funcionário'. Se não estiver, o usuário não será autorizado e a resposta será 403 proibida.
Usando a entrada do Kubernetes e gateways de API do Ocelot
Ao usar o Kubernetes (como em um cluster do Serviço de Kubernetes do Azure), você geralmente unifica todas as solicitações HTTP por meio da camada de Entrada do Kubernetes com base 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), atuando como um proxy reverso.
Como definição, uma entrada é uma coleção de regras que permitem que conexões de entrada cheguem aos 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 entrada por posting do recurso de entrada para o servidor de API.
No eShopOnContainers, ao desenvolver localmente e usar apenas seu computador 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" com base 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 roteados para vários Gateways de API ou BFF.
Os Gateways de API são front-ends ou fachadas que exibem apenas os serviços, mas não os aplicativos Web que geralmente estão fora do escopo. Além disso, os Gateways de API podem ocultar determinados microsserviços internos.
A entrada, no entanto, está apenas redirecionando solicitações HTTP, mas não tentando ocultar nenhum microsserviço ou aplicativo Web.
Ter uma camada Nginx de entrada no Kubernetes na frente dos aplicativos Web, além dos vários Gateways de API do Ocelot/BFF, é a arquitetura ideal, conforme mostrado no diagrama a seguir.
Figura 6-41. A camada de entrada no eShopOnContainers quando implantada no Kubernetes
Uma Entrada do Kubernetes 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 eShopOnContainers no Kubernetes, ele expõe apenas alguns serviços ou pontos de extremidade por meio da entrada, basicamente a seguinte lista de postfixes nas URLs:
-
/para o aplicativo Web SPA cliente -
/webmvcpara o aplicativo Web MVC do cliente -
/webstatuspara o aplicativo Web cliente mostrando o status/verificações de integridade -
/webshoppingapigwpara o BFF web e os processos de negócios de compras -
/webmarketingapigwpara o BFF web e processos de negócios de marketing -
/mobileshoppingapigwpara o BFF móvel e os processos de negócios de compras -
/mobilemarketingapigwpara o BFF móvel e os processos de negócios de marketing
Ao implantar no Kubernetes, cada Gateway de API do Ocelot está usando um arquivo "configuration.json" diferente para cada pod que executa os Gateways de API. Esses arquivos "configuration.json" são fornecidos pela montagem (originalmente com o script deploy.ps1) um volume criado com base em um mapa de configuração do Kubernetes chamado 'ocelot'. 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 originais "configuration.json" podem ser encontrados dentro da k8s/ocelot/ pasta. Há um arquivo para cada BFF/APIGateway.
Recursos adicionais de corte cruzado em um Gateway de API do Ocelot
Há outros recursos importantes para pesquisar e usar, ao usar um Gateway de API Ocelot, descrito nos links a seguir.
Descoberta de serviço no lado do cliente integrando o Ocelot ao Consul ou Eureka
https://ocelot.readthedocs.io/en/latest/features/servicediscovery.htmlCache na camada de Gateway de API
https://ocelot.readthedocs.io/en/latest/features/caching.htmlRegistro em log na camada de Gateway de API
https://ocelot.readthedocs.io/en/latest/features/logging.htmlQualidade do Serviço (Repetições e Disjuntores) na camada do Gateway de API
https://ocelot.readthedocs.io/en/latest/features/qualityofservice.htmlLimitação de taxa
https://ocelot.readthedocs.io/en/latest/features/ratelimiting.htmlSwagger para Ocelot
https://github.com/Burgyn/MMLib.SwaggerForOcelot