再谈基于Ocelot API网关和IdentityServer的API认证与授权
在《再谈使用IdentityServer实现ASP.NET Core Web API的认证与授权》一文中,我又重新总结了IdentityServer中ApiScope和ApiResource的用法,通过对两者的设置,实现了基于Claim的API授权。今天,我们更进一步,引入Ocelot API网关,并由Ocelot API网关来传递Claims实现授权。
理论上讲,在引入Ocelot API网关后,API的访问授权可以有以下三种模式:
这里就需要在API中,对获取的Access Token进行解析,由于我们已经获得了Access Token,所以,从流程上看,并不需要API再去访问IdentityServer来验证Access Token,只需要解析就可以了。在API中添加下面的代码:
注意其中的scope Claim,也正是我们在进行基于ApiScope授权时所需要的。
重新启用API中被注释掉的授权相关的代码,再次调试API,如果在获取Access Token时,包含了management.read的Scope:
则可以访问GET方法:
但如果在请求Access Token的时候,没有包含management.read Scope:
则访问API就会得到403 Forbidden的错误:
- 完全由Ocelot托管,只需要在配置中设置RouteClaimsRequirement即可
- 由API自己处理,使用Identity中的Claims信息来设置授权策略
- 由API自己处理,Ocelot仅将Claims信息传递给API,API使用自定义逻辑完成授权
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer("management-provider-key", options =>
{
options.Authority = idsAuthority;
options.Audience = "management";
});
当然,这里有必要列出所使用的Ocelot的配置文件:
{
"Routes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 9002
}
],
"UpstreamPathTemplate": "/meeting-room-service/{everything}",
"UpstreamHttpMethod": [
"Get",
"Post",
"Put",
"Patch",
"Delete",
"Options"
],
"SwaggerKey": "MeetingRoomService",
"AuthenticationOptions": {
"AuthenticationProviderKey": "management-provider-key",
"AllowedScopes": [
"management.read",
"management.create"
]
},
"AddClaimsToRequest": {
"scope": "Claims[scope] > value"
}
}
]
}
此处定义了一个API端点的路由逻辑,并且在AuthenticationOptions配置中,设置了以下几个参数:
- AuthenticationProviderKey:与上文C#代码中AddJwtBearer方法调用的第一个参数匹配,表示这个API端点将使用之前所设置的那个Jwt Bearer认证方式相匹配,而在AddJwtBearer方法中,已经说明了Audience为management
- AllowedScopes表示该API所允许的ApiScope有哪些,可以参考前一篇文章来了解细节
这里就需要在API中,对获取的Access Token进行解析,由于我们已经获得了Access Token,所以,从流程上看,并不需要API再去访问IdentityServer来验证Access Token,只需要解析就可以了。在API中添加下面的代码:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = CreateTokenValidationParameters();
});
app.UseAuthentication();
static TokenValidationParameters CreateTokenValidationParameters() => new()
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateIssuerSigningKey = false,
SignatureValidator = delegate (string token, TokenValidationParameters parameters)
{
var jwt = new JwtSecurityToken(token);
return jwt;
},
RequireExpirationTime = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
RequireSignedTokens = false
};
此时再次启动调试,查看User Claims,可以看到,我们已经能够拿到正确的值:
注意其中的scope Claim,也正是我们在进行基于ApiScope授权时所需要的。
重新启用API中被注释掉的授权相关的代码,再次调试API,如果在获取Access Token时,包含了management.read的Scope:
则可以访问GET方法:
但如果在请求Access Token的时候,没有包含management.read Scope:
则访问API就会得到403 Forbidden的错误:

浙公网安备 33010602011771号