8 c# jwt asp.net-core asp.net-core-2.1
我正在 ASP.NET Core 2.1 上开发一个授权系统,它需要在授予访问权限之前遵守资源级别和范围。也就是说,我必须是一本书的作者(可以有多个),并且必须具有必要的范围(“write.book”、“read.book”、“delete.book”等)。我在 中成功配置了 JWT Startup.cs,并401s在传递无效令牌时接收。我遇到的问题是强制执行范围。 policy.RequireClaim("scope", "write.book")当访问令牌只需要一个必需的范围时有效,但访问令牌包含多个范围总是失败"write.book delete.book"。如何将策略配置为需要可能是访问令牌包含的范围子集的范围列表?我没有看到任何Policy接受范围列表的方法,所以我假设框架只是执行字符串比较,这就是授权失败的原因。write.book != write.book delete.book. 澄清一下,如果策略只需要一个 scope write.book,但访问令牌中存在多个write.book delete.book,则授权失败。
下面的代码仅在访问令牌包含一个范围时有效,如果存在多个则失败。
authorization.AddPolicy("writeBookPolicy", policy => {
policy.RequireAuthenticatedUser().AddAuthenticationSchemes("Bearer")
.RequireClaim("scope", "write.book").Build();
});
{"scope": "write.book"} // Works
{"scope": "write.book delete.book"} //Fails
Run Code Online (Sandbox Code Playgroud)
您必须使用更复杂的索赔检查。使用RequireAssertion()替代和解析出的范围要求:
var scopes = new[] { "write.book", "delete.book" };
builder.RequireAssertion(context => {
var claim = context.User.FindFirst("scope");
if(claim == null) { return false; }
return claim.Value.Split(' ').Any(s =>
scopes.Contains(s, StringComparer.OrdinalIgnoreCase)
);
});
Run Code Online (Sandbox Code Playgroud)
我写了一个小扩展方法,虽然不太容易阅读,但更容易使用:
private static readonly IEnumerable<string> _scopeClaimTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase) {
"http://schemas.microsoft.com/identity/claims/scope",
"scope"
};
public static AuthorizationPolicyBuilder RequireScope(this AuthorizationPolicyBuilder builder, params string[] scopes) {
return builder.RequireAssertion(context =>
context.User
.Claims
.Where(c => _scopeClaimTypes.Contains(c.Type))
.SelectMany(c => c.Value.Split(' '))
.Any(s => scopes.Contains(s, StringComparer.OrdinalIgnoreCase))
);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4929 次 |
| 最近记录: |