NetCore Ocelot 之 Authentication

发布时间 2023-10-08 17:24:42作者: 云霄宇霁

In order to authenticate Routes and subsequently use any of Ocelot's claims based features such as authorization or modifying the request with values from the token. Users must register authentication services in their Startup.cs as usual but they provide a scheme(auhentication provider key) with each registration.e.g.

var authenticationProviderKey = "authenticationkey";
builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddIdentityServerAuthentication(authenticationProviderKey, options =>
    {
        options.Authority = "https://localhost:9000";
        options.RequireHttpsMetadata = false;
        options.ApiName = "APIResource1";
        options.SupportedTokens = SupportedTokens.Both;
        options.JwtBearerEvents = new JwtBearerEvents  
        {
            OnChallenge = ctx => 
            {
                return Task.CompletedTask;
            },
            OnMessageReceived = ctx => 
            {
                var token = ctx.Token;
                return Task.CompletedTask;
            },
            OnTokenValidated = ctx => 
            {
                var securityToken = ctx.SecurityToken as JwtSecurityToken;
                var claimIdentities = ctx.Principal?.Identities;
                if (claimIdentities?.Any(i => i.Claims.Any(c=> c.Value.Equals("admin", StringComparison.OrdinalIgnoreCase))) ?? false)
                    ctx.Success();
                else
                    ctx.Fail("token validate failed.");
                return Task.CompletedTask;
            },
            OnAuthenticationFailed = context =>
            {
                context.Fail(context.Exception);
                return Task.CompletedTask;
            },
            OnForbidden = context =>
            {
                context.Fail("403 forbidden");
                return Task.CompletedTask;
            }
        };
    });

In this example 'authenticationkey' is the scheme that this provider has been registered with. we then map this to a Route in the configuration e.g.

{
      "DownstreamPathTemplate": "/api/service1",
      "DownstreamScheme": "https",
      "DownstreamHttpMethod": "Get",
      "UpstreamHttpMethod": [ "Options", "Get", "Post", "Put", "Delete" ],
      "UpstreamPathTemplate": "/Ocelot/service1",
      //"UpstreamHost": "localhost",//404 Not found
      "UseServiceDiscovery": true,
      "ServiceName": "serviceA",
      /*
      LeastConnection
      RoundRobin
      NoLoadBalance
      */
      "LoadBalancerOptions": {
        "Type": "CustomRandomLoadBalancer"
      },
      "RateLimitOptions": {
        "ClientWhiteList": [ "NoLimitedAPI" ],
        "EnableRateLimiting": true,
        "Period": "10s", //1s, 5m, 1h, 1d
        "PeriodTimespan": 10, //retry after n second/seconds
        "Limit": 3
      },
      "authenticationoptions": {
        "authenticationproviderkey": "authenticationkey",
        "allowedscopes": [ "apiscope2" ]
      },
      "Key": "service1",
      "Priority": 11
    }

When Ocelot runs it will look at this Routes AuthenticationOptions.AuthenticationProviderKey and check that there is an Authentication provider registered with the given key. If there isn't then Ocelot will not start up, if there is then the Route will use that provider when it executes.

If a Route is authenticated Ocelot will invoke whatever scheme is associated with it while executing the authentication middleware. If the request fails authentication Ocelot returns a http status code 401/403.

Allowed Scopes

If you add scopes to AllowedScopes Ocelot will get all the user claims(from token) of the type scope and make sure that the user has all of the scopes in the list.

This is a way to restric access to a Route on a per scope basis.

IdentityServer4的配置请参考NetCore IdentityServer4,示例IdentityServer4获取的access token如下

{
  "nbf": 1696753665,
  "exp": 1696757265,
  "iss": "https://localhost:9000",
  "aud": [
    "APIResource1",
    "APIResource2"
  ],
  "client_id": "clientId",
  "client_role": "admin",
  "client_nickname": "tom",
  "client_Emai": "tom@163.com",
  "jti": "5EA4ABD33903543E6C9F5151A517AF29",
  "iat": 1696753665,
  "scope": [
    "apiscope1",
    "apiscope2"
  ]
}

这里的aud即authentication middleware中Apiname所允许的API,scope即authenticationoptions.allowedscopes中指定所允许的scope。

如果authentication middleware中 apiname 配置非IdentityServer4 所允许的aud e.g.

options.Authority = "https://localhost:9000";
options.RequireHttpsMetadata = false;
options.ApiName = "APIResource3";
options.SupportedTokens = SupportedTokens.Both;

如果consul.json中配置authenticationoptions.allowedscopes为非IdentityServer4中允许apiscope e.g.

"authenticationoptions": {
        "authenticationproviderkey": "authenticationkey",
        "allowedscopes": [ "apiscope3" ]
      }

 如果配置均正确e.g.