c# - 无法根据 Identity Server 4 中的策略(一般授权)访问安全端点
问题描述
在我的 API 的Startup.cs中,我有以下授权策略。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(...);
...
services.AddAuthorization(options =>
{
options.AddPolicy("VerySecurePolicy", policy =>
{
policy.RequireClaim("admin");
});
options.AddPolicy("VaguelySecurePolicy", policy =>
{
policy.RequireAuthenticatedUser();
});
});
}
然后,我保护了两种操作方法,一种具有无参数属性,一种具有指定的策略。
[Authorize, HttpGet("regular")]
public IActionResult GetRegularData() { return Ok("This is regular level data."); }
[Authorize(Policy = "VerySecurePolicy"), HttpGet("admin")]
public IActionResult GetAdminData() { return Ok("This is admin level data."); }
登录后,我可以访问前者,但不能访问后者。我的推论是索赔管理员没有正确分配给我的用户,我看不到我缺少什么。使用我的访问令牌检查用户信息端点(/connect/userinfo)会给我 ID、电子邮件等,但不是角色admin。检查令牌本身根本没有显示声明数组(只有范围和通常的声明,如sub,exp等)。
这是TestUser
登录的实例。
yield return new TestUser
{
SubjectId = "37cfad39-e4da-486b-a8db-a752565125f8", ...
Claims = new List<Claim>
{
new Claim(JwtClaimTypes.Email, "fakey.uno@touchtech.comm"), ...
new Claim(JwtClaimTypes.Role, "admin")
}
};
声明的API 范围之一包含admin作为声明。我已验证该范围在访问令牌中。我还在这样的API 资源中添加了信息(尽管我不确定它是否真的需要它)。
yield return new ApiScope("test_scope_a1", "Test scope A1", new[] { "admin" });
yield return new ApiResource
{
...
Scopes = new List<string> { "test_scope_a1", ... },
UserClaims = new List<string> { "admin", ... }
};
努力证明:
解决方案
您的VerySecurePolicy
政策设置不正确。像这样定义策略。注意claimType
参数是ClaimTypes.Role
,而不是role
[1]。
options.AddPolicy("VerySecurePolicy", policy => {
policy.RequireClaim(claimType: ClaimTypes.Role, "admin");
});
或者,如果这样更合适,请使用其他 require 方法。
options.AddPolicy("VerySecurePolicy", policy => {
policy.RequireRole("admin");
});
有很多这样的方法,并且可以将它们链接起来以进行复杂的安全定义。
policy.RequireAuthenticatedUser()
.RequireClaim("client_id", "spa_client")
.RequireRole("admin")
.RequireAssertion(context => context.User.Name == "Konrad");
});
您在原始样本中实际拥有的是admin
索赔支票,而不是role: admin
索赔。
此外,您可以访问前一个操作,因为您没有指定策略,也没有默认/后备策略。这意味着[Authorize]
仅确保用户经过身份验证。
为了使其正常工作,您需要明确指定它:
[Authorize("VaguelySecurePolicy"), HttpGet("admin")]
public IActionResult GetRegularData() { return Ok("This is regular level data."); }
或将其设置为后备/默认策略:
services.AddAuthorization(
options => {
options.AddPolicy("VerySecurePolicy", policy => { policy.RequireClaim("role", "admin"); });
//
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
}
);
这可确保带有注释的操作[Authorize]
在没有特定策略集的情况下受回退策略的约束。
[1]:我们没有使用role
声明类型,而是使用它的映射等效项 http://schemas.microsoft.com/ws/2008/06/identity/claims/role
。如果您不希望发生此映射,并引用出现在 JWT 中的声明,则需要禁用映射:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(...).AddJwtBearer(...);
现在role
声明将显示为role
,sub
将sub
如您所期望的那样显示。
请注意,这会破坏许多事情,例如,您现在不能User.IsInRole("rolename")
用于检查角色,因为它期望角色声明类型为ClaimTypes.Role
. 所以我就让它保持原样。
参考
推荐阅读
- xml - 格式化程序功能在 XML 片段中不起作用
- javascript - 如何从离子中的json字符串中检索值
- c++ - CUDA CUFFT/IFFT 如果我填充数据会有不同的结果?
- php - 如何访问从excel文件生成的复杂数组
- c++ - 如何修复这个发生在 35. 代码行的错误
- c# - 如何使我的 fastcolored 文本框透明?
- mysql - MariaDB 上的 MySQL 查询非常慢
- c - 第二个 fget 后的分段错误
- swift - Extension to generic struct where element is generic struct
- python - 比较嵌套字典中的最小值