IsInRole return false 即使声明中有角色

IsInRole return false even if there is role in claims

我正在处理基于声明的身份验证,它运行良好。 现在我想添加角色授权。 我有用户的角色声明(例如 "Admin")

When the IsInRole() method is called, there is a check made to see if the current user has that role. In claims-aware applications, the role is expressed by a role claim type that should be available in the token. The role claim type is expressed using the following 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);

如果我检查用户是否在角色中,我会得到错误。虽然我有 "Admin" 值

的角色声明
User.IsInRole("Admin");

同时在我的 api 上授权属性将不起作用

[Authorize (Roles = "Admin")]

我可能无法理解如何使角色对用户可见。仅在声明列表中包含角色可能还不够?

可能,索赔的 ClaimType 只是 "role"。

您应该使用 Microsoft Schema 创建声明:

manager.AddClaim(dn1.Id, claim: new Claim(ClaimTypes.Role.ToString(), "ADMINISTRATOR"));

那么User.IsInRole("Admin");[Authorize (Roles = "Admin")]就可以正常工作了。

这是因为 Microsoft Identity 使用架构:

http://schemas.microsoft.com/ws/2008/06/identity/claims/role

何时进行角色检查。 我建议您检查 ASPNETIdentity 数据库以全面了解如何插入声明。 我很确定 AspNetUserClaims 的 ClaimType 与 Microsoft Schema 不同。

此致

如果您的服务使用 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 获得。有关替代方法,请参阅

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,但您可能也做了同样的事情...

您没有提到您使用的是哪种身份验证方法,但是如果您使用的是 JWT 身份验证,那么您需要在生成令牌时将角色添加到 ClaimsIdentity,详见 post:ASP.NET Core JWT mapping role claims to ClaimsIdentity

注意 HttpContext.User.Identity.RoleClaimType: "角色"

可能与 ClaimTypes.Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"

因此,在生成声明标识时,您可能需要使用“角色”作为键而不是 ClaimTypes 常量来添加声明。 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;

第一个添加确实是多余的,但让我觉得我实际上是在添加正确的声明。