IsInRole 返回 false,即使声明中有角色
本文关键字:声明 角色 返回 false IsInRole | 更新日期: 2023-09-27 18:32:28
我正在研究基于声明的身份验证,它工作正常。现在我想添加角色自动化。我有用户的角色声明(例如。"管理员"(
调用 IsInRole(( 方法时,会进行检查以查看是否 当前用户具有该角色。在声明感知应用程序中,角色 由应在 令 牌。角色声明类型使用以下 URI 表示: http://schemas.microsoft.com/ws/2008/06/identity/claims/role
//Include all claims
//claims is List<Claim> with all claims
var id = new ClaimsIdentity(claims, "Cookies");
Request.GetOwinContext().Authentication.SignIn(id);
如果我检查用户是否在角色中,我会得到假。虽然我有带有"管理员"值的角色声明
User.IsInRole("Admin");
也授权我的 api 上的属性将不起作用
[Authorize (Roles = "Admin")]
我可能不知道如何使角色对用户可见的逻辑。在声明列表中仅包含角色可能还不够?
如果您的服务使用的是 Windows 身份验证,则您收到的IPrincipal.Identity
将为 WindowsPrincipal
类型。这有点误导,但WindowsPrincipal.IsInRole()
寻找的ClaimType
并不像您合理预期的那样ClaimTypes.Role
,而是ClaimTypes.GroupSid
。
但是,不应假定当前标识用于指定角色的实际 ClaimType,因为不同类型的标识使用不同的值。 相反,您应该引用 ClaimsIdentity.RoleClaimType
属性。
我们按照以下思路实施了一项IAuthenticationFilter
:
public Task AuthenticateAsync(HttpAuthenticationContext context, cancellationToken)
{
var principal = context.Principal;
if(principal.Identity is ClaimsIdentity && principal.Identity.IsAuthenticated)
{
var ci = (ClaimsIdentity)principal.Identity;
// get the user's additional roles from somewhere and add Claims
ci.AddClaim(new Claim(ci.RoleClaimType, "MyRole"));
}
}
这允许我们在 ASP.Net 控制器中使用标准的 AuthorizeAttribute 机制。
[Authorize(Roles="MyRole")]
public IHttpActionResult Get()
{
//authenticated and authorised code here
}
有关进一步的说明,请参阅 MSDN 上的 ClaimsIdentity.RoleClaimType。
请注意:将用户定义的角色添加到WindowsPrincipal
可能会导致问题。似乎.Net Framework 4.5的当前实现(截至2017年4月(有时会在检查角色时引发异常,期望角色的详细信息可从Active Directory获得。 有关替代方法,请参阅此问题。
声明的 ClaimType 可能只是"角色"。
应使用Microsoft架构创建声明:
manager.AddClaim(dn1.Id, claim: new Claim(ClaimTypes.Role.ToString(), "ADMINISTRATOR"));
然后User.IsInRole("Admin");
和[Authorize (Roles = "Admin")]
将正常工作。
这是因为Microsoft标识使用架构:
http://schemas.microsoft.com/ws/2008/06/identity/claims/role
何时进行角色检查。我建议您检查ASPNETIdentity数据库,以全面了解che声明是如何插入的。我很确定AspNetUserClaims的ClaimType不像Microsoft模式。
问候
TL;DR 区分大小写,也许?
我发现默认情况下使用的支票
... [Authorize(Roles = "RoleA,RoleB")]
。区分大小写。
我创建了混合大小写的角色,并使用了 AspNetCore 的标识管理器和非 EF 内存实现进行测试。
UserManager.IsInRole("RoleA"( 返回 true,但当通过 ClaimsPrincipal 检查时,HttpContext.User.IsInRole("RoleA"( 返回 false。 我将声明转储到文本中,可以看到正确的 MS 架构存在角色声明......
ClaimType:[http://schemas.microsoft.com/ws/2008/06/identity/claims/role], ClaimValue:[ROLEA], Issuer:[TokenServer]
ClaimType:[http://schemas.microsoft.com/ws/2008/06/identity/claims/role], ClaimValue:[ROLEB], Issuer:[TokenServer]
。但声明值(角色(是大写的。
要解决此问题,我只需要将属性更改为...
[Authorize(Roles = "ROLEA,ROLEB")]
。它奏效了。
因此,如果在获取角色授权以在 AspNetCore 中工作时遇到问题,请尝试读取声明,并完全匹配声明。 您可以通过访问 HttpContext.User.Claims 对象来读取声明...
foreach (var claim in HttpContext.User.Claims)
Console.WriteLine($"ClaimType:[{claim.Type}], ClaimValue:[{claim.Value}], Issuer:[{claim.Issuer}]");
当然,可能是我以某种方式将角色编码为大写,或者在某处使用了 NormalisedRole,但您可能做了同样的事情......
注意HttpContext.User.Identity.RoleClaimType: "role">
可能与ClaimTypes.Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role">
因此,在生成声明标识时,可能需要使用"role"作为键而不是 ClaimType 常量添加声明。ClaimsIdentity.IsInRole(String( 使用 ClaimsIdentity.RoleClaimType 定义的声明键。
我的工厂代码看起来像这样...
var identity = await base.GenerateClaimsAsync(user);
var roles = await UserManager.GetRolesAsync(user);
foreach (var role in roles)
{
identity.AddClaim(new Claim(ClaimTypes.Role, role));
identity.AddClaim(new Claim("role", role));
}
return identity;
第一次添加确实是多余的,但让我觉得我实际上是在添加正确的声明。
您没有提到您使用的是哪种身份验证方法,但是如果您使用的是 JWT 身份验证,则需要在生成令牌时将角色添加到 ClaimsIdentity,如本文中所述: ASP.NET 核心 JWT 将角色声明映射到 ClaimsIdentity