In a regular type scenario, where a Route is available, say to only "Premium" users, ocelot.global.json
would have RouteClaimsRequirement
like this:
"RouteClaimsRequirement" : { "Role" : "Premium" }
This would get translated to a KeyValuePair<string, string>()
, and it works nicely.
However, if I were to open a route to 2 types of users, eg. "Regular" and "Premium", how exactly could I achieve this?
I found a way through overriding of default Ocelot middleware. Here are some useful code snippets:
First, override the default AuthorizationMiddleware in Configuration() in Startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
var config = new OcelotPipelineConfiguration
{
AuthorisationMiddleware
= async (downStreamContext, next) =>
await OcelotJwtMiddleware.CreateAuthorizationFilter(downStreamContext, next)
};
app.UseOcelot(config).Wait();
}
As you can see, I am using a custom OcelotJwtMiddleware class up there. Here is that class, pasted:
public static class OcelotJwtMiddleware
{
private static readonly string RoleSeparator = ",";
public static Func<DownstreamContext, Func<Task>, Task> CreateAuthorizationFilter
=> async (downStreamContext, next) =>
{
HttpContext httpContext = downStreamContext.HttpContext;
var token = httpContext.Request.Cookies[JwtManager.AuthorizationTokenKey];
if (token != null && AuthorizeIfValidToken(downStreamContext, token))
{
await next.Invoke();
}
else
{
downStreamContext.DownstreamResponse =
new DownstreamResponse(new HttpResponseMessage(HttpStatusCode.Unauthorized));
}
};
private static bool AuthorizeIfValidToken(DownstreamContext downStreamContext, string jwtToken)
{
IIdentityProvider decodedObject = new JwtManager().Decode<UserToken>(jwtToken);
if (decodedObject != null)
{
return downStreamContext.DownstreamReRoute.RouteClaimsRequirement["Role"]
?.Split(RoleSeparator)
.FirstOrDefault(role => role.Trim() == decodedObject.GetRole()) != default;
}
return false;
}
}
JwtManager class here is just my small utility made using the default Jwt NuGet package, nothing special. Also, JWT is being stored as a Cookie, which is not safe, but doesn't matter here. If you happen to copy paste your code, you will have small errors relating to this, but just switch it out with your own implementations of auth tokens. After these 2 snippets were implemented, ocelot.global.json can have RouteClaimsRequirement such as this:
"RouteClaimsRequirement" : { "Role" : "Premium, Regular" }
This will recognize both clients with Regular in their Cookies, as well as those with Premium.