API-gateways implementeren met Ocelot
Tip
Deze inhoud is een fragment uit het eBook, .NET Microservices Architecture for Containerized .NET Applications, beschikbaar op .NET Docs of als een gratis downloadbare PDF die offline kan worden gelezen.
Belangrijk
De referentie-microservicetoepassing eShopOnContainers gebruikt momenteel functies van Envoy om de API Gateway te implementeren in plaats van de eerder gebruikte Ocelot. We hebben deze ontwerpkeuze gemaakt vanwege de ingebouwde ondersteuning van Envoy voor het WebSocket-protocol, vereist door de nieuwe gRPC interservicecommunicatie geïmplementeerd in eShopOnContainers. We hebben deze sectie echter bewaard in de handleiding, zodat u Ocelot kunt beschouwen als een eenvoudige, geschikte en lichtgewicht API Gateway die geschikt is voor scenario's op productieniveau. Bovendien bevat de nieuwste Ocelot-versie een belangrijke wijziging in het json-schema. Overweeg ocelot < v16.0.0 te gebruiken of gebruik de belangrijkste routes in plaats van ReRoutes.
Uw API-gateways ontwerpen en ontwerpen
In het volgende architectuurdiagram ziet u hoe API-gateways zijn geïmplementeerd met Ocelot in eShopOnContainers.
Afbeelding 6-28. Architectuur van eShopOnContainers met API Gateways
In dit diagram ziet u hoe de hele toepassing wordt geïmplementeerd in één Docker-host of ontwikkelcomputer met Docker voor Windows of Docker voor Mac. Het implementeren in een orchestrator zou echter vergelijkbaar zijn, maar elke container in het diagram kan worden uitgeschaald in de orchestrator.
Daarnaast moeten de infrastructuurassets, zoals databases, cache en berichtenbrokers, worden offload van de orchestrator en geïmplementeerd in hoge beschikbare systemen voor infrastructuur, zoals Azure SQL Database, Azure Cosmos DB, Azure Redis, Azure Service Bus of een oplossing voor ha-clustering on-premises.
Zoals u ook in het diagram kunt zien, kunnen meerdere API-gateways meerdere ontwikkelteams autonoom zijn (in dit geval marketingfuncties versus winkelfuncties) bij het ontwikkelen en implementeren van hun microservices plus hun eigen gerelateerde API-gateways.
Als u één monolithische API-gateway had, betekent dit dat er één punt moet worden bijgewerkt door verschillende ontwikkelteams, die alle microservices met één deel van de toepassing kunnen koppelen.
Veel verdergaan in het ontwerp, soms kan een fijnmazige API-gateway ook worden beperkt tot één zakelijke microservice, afhankelijk van de gekozen architectuur. Als u de grenzen van de API Gateway hebt bepaald door het bedrijf of domein, kunt u een beter ontwerp krijgen.
Fijn granulariteit in de API Gateway-laag kan bijvoorbeeld vooral nuttig zijn voor geavanceerdere samengestelde UI-toepassingen die zijn gebaseerd op microservices, omdat het concept van een fijnmazige API-gateway vergelijkbaar is met een UI-samenstellingsservice.
In de vorige sectie gaan we dieper in op het maken van een samengestelde gebruikersinterface op basis van microservices.
Voor veel middelgrote en grote toepassingen is het gebruik van een aangepast API Gateway-product meestal een goede aanpak, maar niet als één monolithische aggregator of unieke centrale aangepaste API Gateway, tenzij api Gateway meerdere onafhankelijke configuratiegebieden toestaat voor de verschillende ontwikkelteams die autonome microservices maken.
Voorbeeld van microservices/containers om te routeren via de API-gateways
EShopOnContainers heeft bijvoorbeeld ongeveer zes interne microservicetypen die moeten worden gepubliceerd via de API-gateways, zoals wordt weergegeven in de volgende afbeelding.
Afbeelding 6-29. Microservicemappen in de oplossing eShopOnContainers in Visual Studio
Over de Identity-service, in het ontwerp wordt het weggelaten uit de API Gateway-routering omdat het de enige cross-cutting zorg in het systeem is, hoewel ocelot het ook mogelijk is om het op te nemen als onderdeel van de omleidingslijsten.
Al deze services worden momenteel geïmplementeerd als ASP.NET Core Web API-services, zoals u kunt zien in de code. Laten we ons richten op een van de microservices, zoals de Catalogus-microservicecode.
Afbeelding 6-30. Voorbeeld van web-API-microservice (catalogusmicroservice)
U kunt zien dat de Microservice Catalogus een typisch ASP.NET Core Web API-project is met verschillende controllers en methoden, zoals in de volgende code.
[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();
}
De HTTP-aanvraag wordt uiteindelijk uitgevoerd met dat soort C#-code die toegang heeft tot de microservicedatabase en eventuele aanvullende vereiste actie.
Met betrekking tot de microservice-URL, wanneer de containers worden geïmplementeerd op uw lokale ontwikkel-pc (lokale Docker-host), heeft de container van elke microservice altijd een interne poort (meestal poort 80) die is opgegeven in het dockerfile, zoals in de volgende dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
De poort 80 die in de code wordt weergegeven, is intern binnen de Docker-host, zodat deze niet kan worden bereikt door client-apps.
Client-apps hebben alleen toegang tot de externe poorten (indien aanwezig) die zijn gepubliceerd bij het implementeren met docker-compose
.
Deze externe poorten mogen niet worden gepubliceerd wanneer ze worden geïmplementeerd in een productieomgeving. Om deze specifieke reden, waarom u de API Gateway wilt gebruiken, om de directe communicatie tussen de client-apps en de microservices te voorkomen.
Bij het ontwikkelen wilt u echter rechtstreeks toegang krijgen tot de microservice/container en deze uitvoeren via Swagger. Daarom worden in eShopOnContainers de externe poorten nog steeds opgegeven, zelfs wanneer ze niet worden gebruikt door de API Gateway of de client-apps.
Hier volgt een voorbeeld van het docker-compose.override.yml
bestand voor de microservice Catalogus:
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).
U kunt zien hoe in de docker-compose.override.yml configuratie de interne poort voor de cataloguscontainer poort 80 is, maar de poort voor externe toegang is 5101. Maar deze poort mag niet worden gebruikt door de toepassing wanneer u een API-gateway gebruikt, alleen om fouten op te sporen, uit te voeren en alleen de microservice Catalogus te testen.
Normaal gesproken implementeert u niet met docker-compose in een productieomgeving, omdat de juiste productie-implementatieomgeving voor microservices een orchestrator is zoals Kubernetes of Service Fabric. Wanneer u implementeert in deze omgevingen, gebruikt u verschillende configuratiebestanden waar u geen directe externe poort voor de microservices publiceert, maar u gebruikt altijd de omgekeerde proxy van de API Gateway.
Voer de catalogusmicroservice uit in uw lokale Docker-host. Voer de volledige eShopOnContainers-oplossing uit vanuit Visual Studio (hiermee worden alle services in de docker-compose-bestanden uitgevoerd) of start u de Microservice Catalog met de volgende docker-compose-opdracht in CMD of PowerShell die is geplaatst in de map waar de docker-compose.yml
en docker-compose.override.yml
worden geplaatst.
docker-compose run --service-ports catalog-api
Met deze opdracht wordt alleen de servicecontainer catalog-API plus afhankelijkheden uitgevoerd die zijn opgegeven in de docker-compose.yml. In dit geval de SQL Server-container en RabbitMQ-container.
Vervolgens kunt u rechtstreeks toegang krijgen tot de Microservice catalogus en de methoden ervan bekijken via de Swagger-gebruikersinterface die rechtstreeks via die externe poort toegang heeft, in dit geval http://host.docker.internal:5101/swagger
:
Afbeelding 6-31. De catalogusmicroservice testen met de Swagger-gebruikersinterface
Op dit moment kunt u een onderbrekingspunt instellen in C#-code in Visual Studio, de microservice testen met de methoden die beschikbaar zijn in de Swagger-gebruikersinterface en ten slotte alles opschonen met de docker-compose down
opdracht.
Communicatie via directe toegang tot de microservice, in dit geval via de externe poort 5101, is echter precies wat u in uw toepassing wilt vermijden. En u kunt dit voorkomen door het extra niveau van indirectie van de API-gateway (Ocelot, in dit geval) in te stellen. Op die manier heeft de client-app niet rechtstreeks toegang tot de microservice.
Uw API-gateways implementeren met Ocelot
Ocelot is in feite een set middleware die u in een specifieke volgorde kunt toepassen.
Ocelot is alleen ontworpen voor gebruik met ASP.NET Core. De nieuwste versie van het pakket is 18.0 die gericht is op .NET 6 en daarom niet geschikt is voor .NET Framework-toepassingen.
U installeert Ocelot en de bijbehorende afhankelijkheden in uw ASP.NET Core-project met het NuGet-pakket van Ocelot, vanuit Visual Studio.
Install-Package Ocelot
In eShopOnContainers is de API Gateway-implementatie een eenvoudig ASP.NET Core WebHost-project en de middleware van Ocelot verwerkt alle API Gateway-functies, zoals wordt weergegeven in de volgende afbeelding:
Afbeelding 6-32. Het ocelotApiGw-basisproject in eShopOnContainers
Dit ASP.NET Core WebHost-project is gebouwd met twee eenvoudige bestanden: Program.cs
en Startup.cs
.
De Program.cs hoeft alleen de typische ASP.NET Core BuildWebHost te maken en te configureren.
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;
}
}
}
Het belangrijkste punt hier voor Ocelot is het configuration.json
bestand dat u aan de opbouwfunctie moet verstrekken via de AddJsonFile()
methode. Hier configuration.json
geeft u alle API Gateway-reroutes op, wat betekent dat de externe eindpunten met specifieke poorten en de gecorreleerde interne eindpunten, meestal met behulp van verschillende poorten.
{
"ReRoutes": [],
"GlobalConfiguration": {}
}
Er zijn twee secties voor de configuratie. Een matrix van ReRoutes en een GlobalConfiguration. De ReRoutes zijn de objecten die Ocelot vertellen hoe een upstream-aanvraag moet worden behandeld. De algemene configuratie staat onderdrukkingen van specifieke ReRoute-instellingen toe. Het is handig als u niet veel specifieke ReRoute-instellingen wilt beheren.
Hier volgt een vereenvoudigd voorbeeld van een ReRoute-configuratiebestand van een van de API-gateways uit 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"
}
}
De belangrijkste functionaliteit van een Ocelot-API-gateway is het aannemen van binnenkomende HTTP-aanvragen en deze doorsturen naar een downstreamservice, momenteel als een andere HTTP-aanvraag. Ocelot beschrijft de routering van de ene aanvraag naar een andere als een ReRoute.
Laten we ons bijvoorbeeld richten op een van de ReRoutes in de configuration.json hierboven, de configuratie voor de Basket-microservice.
{
"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 en DownstreamHostAndPorts maken de interne microservice-URL waarnaar deze aanvraag wordt doorgestuurd.
De poort is de interne poort die door de service wordt gebruikt. Wanneer u containers gebruikt, wordt de poort die is opgegeven in het dockerfile.
Dit Host
is een servicenaam die afhankelijk is van de servicenaamomzetting die u gebruikt. Wanneer u docker-compose gebruikt, worden de servicesnamen geleverd door de Docker-host. Hierbij worden de servicenamen gebruikt die zijn opgegeven in de docker-compose-bestanden. Als u een orchestrator zoals Kubernetes of Service Fabric gebruikt, moet die naam worden omgezet door de DNS- of naamomzetting die door elke orchestrator wordt geleverd.
DownstreamHostAndPorts is een matrix die de host en poort bevat van downstreamservices waarnaar u aanvragen wilt doorsturen. Meestal bevat deze configuratie slechts één vermelding, maar soms wilt u misschien aanvragen verdelen over uw downstreamservices en Ocelot kunt u meer dan één vermelding toevoegen en vervolgens een load balancer selecteren. Maar als u Azure en een orchestrator gebruikt, is het waarschijnlijk een beter idee om taken te verdelen met de cloud- en orchestratorinfrastructuur.
De UpstreamPathTemplate is de URL die Ocelot gebruikt om te bepalen welke DownstreamPathTemplate moet worden gebruikt voor een bepaalde aanvraag van de client. Ten slotte wordt de UpstreamHttpMethod gebruikt, zodat Ocelot onderscheid kan maken tussen verschillende aanvragen (GET, POST, PUT) naar dezelfde URL.
Op dit moment kunt u één Ocelot-API-gateway (ASP.NET Core WebHost) gebruiken met behulp van een of meerdere samengevoegde configuration.json bestanden of kunt u de configuratie ook opslaan in een Consul KV-archief.
Maar zoals geïntroduceerd in de secties architectuur en ontwerp, als u echt autonome microservices wilt hebben, is het misschien beter om die monolithische API-gateway op te splitsen in meerdere API-gateways en/of BFF (back-end voor front-end). Laten we daarom eens kijken hoe u die aanpak implementeert met Docker-containers.
Eén Docker-containerinstallatiekopieën gebruiken om meerdere verschillende API Gateway-/BFF-containertypen uit te voeren
In eShopOnContainers gebruiken we één Docker-containerinstallatiekopie met de Ocelot-API-gateway, maar vervolgens maken we tijdens runtime verschillende services/containers voor elk type API-Gateway/BFF door een ander configuration.json-bestand op te geven met behulp van een docker-volume voor toegang tot een andere pc-map voor elke service.
Afbeelding 6-33. Eén Ocelot Docker-installatiekopie hergebruiken voor meerdere API-gatewaytypen
In eShopOnContainers wordt de 'Generic Ocelot API Gateway Docker Image' gemaakt met het project met de naam 'OcelotApiGw' en de installatiekopienaam 'eshop/ocelotapigw' die is opgegeven in het docker-compose.yml bestand. Wanneer u vervolgens implementeert in Docker, worden er vier API-Gateway-containers gemaakt op basis van dezelfde Docker-installatiekopieën, zoals wordt weergegeven in het volgende extract uit het docker-compose.yml-bestand.
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
Zoals u in het volgende docker-compose.override.yml bestand kunt zien, is het enige verschil tussen deze API Gateway-containers het Ocelot-configuratiebestand. Dit is verschillend voor elke servicecontainer en wordt tijdens runtime opgegeven via een Docker-volume.
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
Vanwege die vorige code en zoals weergegeven in de Visual Studio Explorer hieronder, is het enige bestand dat nodig is om elke specifieke business/BFF API-gateway te definiëren slechts een configuration.json bestand, omdat de vier API-gateways zijn gebaseerd op dezelfde Docker-installatiekopieën.
Afbeelding 6-34. Het enige bestand dat nodig is om elke API Gateway/BFF met Ocelot te definiëren, is een configuratiebestand
Door de API-gateway te splitsen in meerdere API-gateways, kunnen verschillende ontwikkelteams die zich richten op verschillende subsets van microservices hun eigen API-gateways beheren met behulp van onafhankelijke Ocelot-configuratiebestanden. Bovendien kunnen ze dezelfde Ocelot Docker-installatiekopie opnieuw gebruiken.
Als u nu eShopOnContainers uitvoert met de API-gateways (standaard opgenomen in VS bij het openen van eShopOnContainers-ServicesAndWebApps.sln oplossing of als u docker-compose up uitvoert), worden de volgende voorbeeldroutes uitgevoerd.
Wanneer u bijvoorbeeld de upstream-URL http://host.docker.internal:5202/api/v1/c/catalog/items/2/
bezoekt die wordt geleverd door de webshoppingapigw API Gateway, krijgt u hetzelfde resultaat van de interne downstream-URL http://catalog-api/api/v1/2
binnen de Docker-host, zoals in de volgende browser.
Afbeelding 6-35. Toegang tot een microservice via een URL die wordt geleverd door de API Gateway
Vanwege test- of foutopsporingsredenen, als u rechtstreeks toegang wilt hebben tot de Docker-container catalogiseren (alleen in de ontwikkelomgeving) zonder de API-gateway te passeren, omdat 'catalog-api' een INTERNE DNS-omzetting is voor de Docker-host (servicedetectie die wordt verwerkt door docker-compose-servicenamen), is de enige manier om rechtstreeks toegang te krijgen tot de container via de externe poort die in de docker-compose.override.yml is gepubliceerd, die alleen wordt verstrekt voor ontwikkelingstests, zoals http://host.docker.internal:5101/api/v1/Catalog/items/1
in de volgende browser.
Afbeelding 6-36. Directe toegang tot een microservice voor testdoeleinden
Maar de toepassing is zo geconfigureerd dat deze toegang heeft tot alle microservices via de API-gateways, niet via de directe poort 'snelkoppelingen'.
Het aggregatiepatroon van de gateway in eShopOnContainers
Zoals eerder is geïntroduceerd, is een flexibele manier om aanvragenaggregatie te implementeren met aangepaste services per code. U kunt ook aanvraagaggregatie implementeren met de functie Aanvraagaggregatie in Ocelot, maar het is mogelijk niet zo flexibel als u nodig hebt. Daarom is de geselecteerde manier om aggregatie in eShopOnContainers te implementeren met een expliciete ASP.NET Core Web API-service voor elke aggregator.
Volgens deze benadering is het samenstellingsdiagram van de API Gateway in werkelijkheid iets uitgebreider wanneer de aggregatorservices worden overwogen die niet worden weergegeven in het diagram met vereenvoudigde globale architectuur dat eerder werd weergegeven.
In het volgende diagram kunt u ook zien hoe de aggregatorservices werken met hun gerelateerde API-gateways.
Afbeelding 6-37. Architectuur van eShopOnContainers met aggregatorservices
Als u verder inzoomt, ziet u in het bedrijfsgebied 'Winkelen' in de volgende afbeelding dat chattiness tussen de client-apps en de microservices wordt verminderd bij het gebruik van de aggregatorservices in de API-gateways.
Afbeelding 6-38. Inzoomen op de Aggregator-services
U kunt zien hoe wanneer in het diagram de mogelijke aanvragen worden weergegeven die afkomstig zijn van de API-gateways, dit complex kan worden. Als u echter het aggregatorpatroon gebruikt, kunt u zien hoe de pijlen in het blauw de communicatie vanuit het perspectief van een client-app vereenvoudigen. Dit patroon helpt niet alleen om de chattiness en latentie in de communicatie te verminderen, het verbetert ook de gebruikerservaring aanzienlijk voor de externe apps (mobiele en beveiligd-WACHTWOORDVERIFICATIE-apps).
In het geval van het bedrijfsgebied Marketing en microservices is het een eenvoudig gebruiksvoorbeeld, dus er was geen noodzaak om aggregators te gebruiken, maar het zou ook mogelijk kunnen zijn, indien nodig.
Verificatie en autorisatie in Ocelot-API-gateways
In een Ocelot-API-gateway kunt u de verificatieservice, zoals een ASP.NET Core Web API-service, gebruiken met behulp van IdentityServer die het verificatietoken levert, hetzij buiten of in de API-gateway.
Omdat eShopOnContainers meerdere API-gateways met grenzen gebruikt op basis van BFF en bedrijfsgebieden, wordt de Identity/Auth-service uit de API-gateways weggelaten, zoals in het volgende diagram geel is gemarkeerd.
Afbeelding 6-39. Positie van de Identiteitsservice in eShopOnContainers
Ocelot biedt echter ook ondersteuning voor het zitten van de Identity/Auth-microservice binnen de grenzen van de API-gateway, zoals in dit andere diagram.
Afbeelding 6-40. Verificatie in Ocelot
Zoals in het vorige diagram wordt weergegeven, vraagt ag, wanneer de identiteitsmicroservice zich onder de API-gateway (AG): 1) AG een verificatietoken aanvraagt van identiteitsmicroservice, 2) De identiteitsmicroservice retourneert token naar AG, 3-4) AG-aanvragen van microservices met behulp van het verificatietoken. Omdat de eShopOnContainers-toepassing de API-gateway heeft gesplitst in meerdere BFF (back-end voor front-end) en API-gateways voor zakelijke gebieden, zou een andere optie zijn geweest om een extra API-gateway te maken voor kruislingse problemen. Die keuze zou eerlijker zijn in een complexere architectuur op basis van microservices met meerdere overschrijdende problemen microservices. Omdat er slechts één kruislingse zorg in eShopOnContainers is, is besloten om de beveiligingsservice uit de API Gateway-realm af te handelen, in het belang van de eenvoud.
Als de app in ieder geval op API Gateway-niveau is beveiligd, wordt de verificatiemodule van de Ocelot-API-gateway eerst bezocht wanneer een beveiligde microservice wordt gebruikt. Hiermee wordt de HTTP-aanvraag omgeleid naar de identiteits- of verificatiemicroservice om het toegangstoken op te halen, zodat u de beveiligde services kunt bezoeken met de access_token.
De manier waarop u met verificatie elke service op API Gateway-niveau beveiligt, is door de AuthenticationProviderKey in te stellen in de bijbehorende instellingen op het configuration.json.
{
"DownstreamPathTemplate": "/api/{version}/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "basket-api",
"Port": 80
}
],
"UpstreamPathTemplate": "/api/{version}/b/{everything}",
"UpstreamHttpMethod": [],
"AuthenticationOptions": {
"AuthenticationProviderKey": "IdentityApiKey",
"AllowedScopes": []
}
}
Wanneer Ocelot wordt uitgevoerd, wordt de ReRoutes AuthenticationOptions.AuthenticationProviderKey bekeken en wordt gecontroleerd of er een verificatieprovider is geregistreerd bij de opgegeven sleutel. Als dat niet zo is, wordt Ocelot niet opgestart. Als dat zo is, gebruikt de ReRoute die provider wanneer deze wordt uitgevoerd.
Omdat de Ocelot WebHost is geconfigureerd met de authenticationProviderKey = "IdentityApiKey"
, die verificatie vereist wanneer die service aanvragen zonder verificatietoken heeft.
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" }
};
});
//...
}
}
}
Vervolgens moet u ook autorisatie instellen met het kenmerk [Autoriseren] voor elke resource die moet worden geopend, zoals de microservices, zoals in de volgende Basket-microservicecontroller.
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{
[Route("api/v1/[controller]")]
[Authorize]
public class BasketController : Controller
{
//...
}
}
De ValidAudiences, zoals 'basket', worden gecorreleerd met de doelgroep die in elke microservice AddJwtBearer()
is gedefinieerd in de ConfigureServices() van de Opstartklasse, zoals in de onderstaande code.
// 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";
});
Als u toegang probeert te krijgen tot een beveiligde microservice, zoals de Basket-microservice met een ReRoute-URL op basis van de API-gateway, http://host.docker.internal:5202/api/v1/b/basket/1
krijgt u een 401 Niet-geautoriseerd, tenzij u een geldig token opgeeft. Als een ReRoute-URL wordt geverifieerd, roept Ocelot daarentegen elk downstreamschema aan (de interne microservice-URL).
Autorisatie bij de ReRoutes-laag van Ocelot. Ocelot ondersteunt autorisatie op basis van claims die na de verificatie zijn geëvalueerd. U stelt de autorisatie op routeniveau in door de volgende regels toe te voegen aan de ReRoute-configuratie.
"RouteClaimsRequirement": {
"UserType": "employee"
}
Wanneer de autorisatie-middleware wordt aangeroepen, zal Ocelot vinden of de gebruiker het claimtype UserType in het token heeft en of de waarde van die claim 'werknemer' is. Als dit niet zo is, wordt de gebruiker niet geautoriseerd en is het antwoord 403 verboden.
Kubernetes Ingress plus Ocelot-API-gateways gebruiken
Wanneer u Kubernetes (zoals in een Azure Kubernetes Service-cluster) gebruikt, kunt u meestal alle HTTP-aanvragen samenvoegen via de Kubernetes-laag voor inkomend verkeer op basis van Nginx.
Als u in Kubernetes geen toegangsbeheerobjectbenadering gebruikt, hebben uw services en pods alleen ip-adressen die alleen routeerbaar zijn door het clusternetwerk.
Maar als u een toegangsbeheerobjectbenadering gebruikt, hebt u een middelste laag tussen internet en uw services (inclusief uw API-gateways), die fungeert als een omgekeerde proxy.
Als definitie is een toegangsbeheerobject een verzameling regels waarmee binnenkomende verbindingen de clusterservices kunnen bereiken. Een inkomend verkeer is geconfigureerd om services extern bereikbaar URL's te bieden, verkeer te verdelen, SSL-beëindiging en meer. Gebruikers vragen inkomend verkeer aan door de toegangsbeheerobjectresource in te stellen op de API-server.
Wanneer u in eShopOnContainers lokaal ontwikkelt en alleen uw ontwikkelcomputer gebruikt als docker-host, gebruikt u geen toegangsbeheerobjecten, maar alleen de meerdere API-gateways.
Bij het richten van een 'productie'-omgeving op basis van Kubernetes gebruikt eShopOnContainers echter een toegangsbeheerobject voor de API-gateways. Op die manier roepen de clients nog steeds dezelfde basis-URL aan, maar worden de aanvragen doorgestuurd naar meerdere API-gateways of BFF.
API-gateways zijn front-ends of gevels die alleen de services bevatten, maar niet de webtoepassingen die meestal buiten hun bereik vallen. Bovendien kunnen de API-gateways bepaalde interne microservices verbergen.
Het toegangsbeheerobject leidt echter alleen HTTP-aanvragen om, maar probeert geen microservice of web-app te verbergen.
Het hebben van een inkomende Nginx-laag in Kubernetes voor de webtoepassingen plus de verschillende Ocelot-API-gateways /BFF is de ideale architectuur, zoals wordt weergegeven in het volgende diagram.
Afbeelding 6-41. De toegangsbeheerlaag in eShopOnContainers wanneer deze wordt geïmplementeerd in Kubernetes
Een Kubernetes-toegangsbeheerobject fungeert als een omgekeerde proxy voor al het verkeer naar de app, met inbegrip van de webtoepassingen, die buiten het bereik van de Api-gateway vallen. Wanneer u eShopOnContainers in Kubernetes implementeert, worden er slechts enkele services of eindpunten beschikbaar gesteld via inkomend verkeer, in feite de volgende lijst met postvoegsels op de URL's:
/
voor de client-BEVEILIGD-WACHTWOORDVERIFICATIE-webtoepassing/webmvc
voor de client-MVC-webtoepassing/webstatus
voor de clientweb-app met de status/statuscontroles/webshoppingapigw
voor het web BFF en bedrijfsprocessen voor winkelen/webmarketingapigw
voor het web BFF en marketing bedrijfsprocessen/mobileshoppingapigw
voor de mobiele BFF- en winkelprocessen/mobilemarketingapigw
voor de mobiele BFF en marketing bedrijfsprocessen
Bij de implementatie in Kubernetes gebruikt elke Ocelot-API-gateway een ander 'configuration.json'-bestand voor elke pod waarop de API-gateways worden uitgevoerd. Deze 'configuration.json'-bestanden worden geleverd door een volume te koppelen (oorspronkelijk met het script deploy.ps1) dat is gemaakt op basis van een Kubernetes-configuratiekaart met de naam ocelot. Elke container koppelt het bijbehorende configuratiebestand in de map met de naam /app/configuration
van de container.
In de broncodebestanden van eShopOnContainers zijn de oorspronkelijke 'configuration.json'-bestanden te vinden in de k8s/ocelot/
map. Er is één bestand voor elke BFF/APIGateway.
Aanvullende geavanceerde functies in een Ocelot-API-gateway
Er zijn andere belangrijke functies die u kunt onderzoeken en gebruiken wanneer u een Ocelot-API-gateway gebruikt, zoals wordt beschreven in de volgende koppelingen.
Servicedetectie aan de clientzijde die Ocelot integreert met Consul of Eureka
https://ocelot.readthedocs.io/en/latest/features/servicediscovery.htmlCaching in de API Gateway-laag
https://ocelot.readthedocs.io/en/latest/features/caching.htmlLogboekregistratie bij de API Gateway-laag
https://ocelot.readthedocs.io/en/latest/features/logging.htmlQuality of Service (nieuwe pogingen en circuitonderbrekers) in de API Gateway-laag
https://ocelot.readthedocs.io/en/latest/features/qualityofservice.htmlSnelheidsbeperking
https://ocelot.readthedocs.io/en/latest/features/ratelimiting.htmlSwagger voor Ocelot
https://github.com/Burgyn/MMLib.SwaggerForOcelot