I have an API Gateway running in .NET Core 3.1
using Ocelot
. Everything works fine as expected.
Now I'm trying to substitute the downstream host during the middleware process.
Here's my configuration.json:
{
"Routes": [
{
"DownstreamPathTemplate": "/api/product/getProduct",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": "44300"
}
],
"UpstreamPathTemplate": "/getProduct"
}
],
"GlobalConfiguration": {
"BaseUrl": "https://localhost:62012/"
}
}
I want to change the Host
in the DownstreamHostAndPorts
at runtime as by this time from grabbing the claims out of the jwt
I will know the tenant the user belongs to therefore know where to route there request.
To be more clear, a request to the gateway comes in at http://localhost:62012/api/getProduct,
Then I get the tenant from the jwt
in the request that made this call and then redirect the request to the relevant api
like so
http://tenant1.com/api/product/getProduct or http://tenant2.com/api/product/getProduct
You need to create custom middleware and inject it after Authentication
middleware. The best extension point would be PreAuthorisationMiddleware
. Assuming you have a service to resolve tenant uri by user claims, something like this:
public interface ITenantHostResolver
{
Task<Uri> Resolve(ClaimsPrincipal claimsPrincipal);
}
In your Startup
class inject the middleware that will override downstream settings:
public void Configure(IApplicationBuilder app)
{
var conf = new OcelotPipelineConfiguration
{
PreAuthorizationMiddleware = async (httpContext, next) =>
{
if(!httpContext.Request.Path.Equals("/api/product/getProduct"))
{
await next.Invoke();
return;
}
var claimsPrincipal = httpContext.User;
var tenantHostResolver = httpContext.RequestServices.GetRequiredService<ITenantHostResolver>();
var tenantHostAndPort = await tenantHostResolver.Resolve(claimsPrincipal);
var downstreamRequest = httpContext.Items.DownstreamRequest();
downstreamRequest.Host = tenantHostAndPort.Host;
downstreamRequest.Port = tenantHostAndPort.Port;
downstreamRequest.Scheme = tenantHostAndPort.Scheme;
await next.Invoke();
}
};
app.UseCustomOcelot(conf).Wait();
}