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")]

我可能不知道如何使角色对用户可见的逻辑。在声明列表中仅包含角色可能还不够?

IsInRole 返回 false,即使声明中有角色

如果您的服务使用的是 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