授权多个角色

Authorize with multiple roles

应用是在asp.net core 3上开发的。当用户有多个角色时,面临授权问题。

用户角色

public enum UserRole
{
   None = 0x0,
   View = 0x1,
   ConfirmAlarm = 0x2,
   ObjectScaling = 0x4,
   SchemeEditor = 0x8,
   ObjectEditor = 0x10
}

索赔

private async Task Authenticate(User user)
{
   var claims = new List<Claim>
   {
      new Claim(ClaimsIdentity.DefaultNameClaimType, user.Login),
      new Claim(ClaimsIdentity.DefaultRoleClaimType, ((UserRole)user.Role).ToString()),
      new Claim("uGroupId", user.GroupId.ToString()),
      new Claim("uInfo", user.Info),
      new Claim("uTheme", user.Theme)
   };
   ClaimsIdentity id = new ClaimsIdentity(claims, "ApplicationCookie", 
   ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
   await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new 
   ClaimsPrincipal(id));
}

控制器方法:

[Authorize(Roles = "View")]
[HttpPost("[action]")]
public async Task<string> SomeAction()
{
   //...some code
}

如果用户拥有 "View, ConfirmAlarm, ObjectScaling, SchemeEditor, ObjectEditor" 的所有可用角色,则他不能被授权使用控制器中的方法。

可能是什么问题?需要创建自定义 AuthorizeAttribute?

更新

添加了两个类: RolesRequirement.cs

public class RolesRequirement : IAuthorizationRequirement
{
    public string RoleName { get; }

    public RolesRequirement(string roleName)
    {
        RoleName = roleName;
    }
}

RoleHandler.cs

public class RoleHandler : AuthorizationHandler<RolesRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RolesRequirement requirement)
    {
        string roles = context.User.Claims.FirstOrDefault(x => x.Type == ClaimsIdentity.DefaultRoleClaimType).Value;
        if (!string.IsNullOrEmpty(roles))
        {
            if (roles.Contains(requirement.RoleName))
            {
                context.Succeed(requirement);
            }
        }

        return Task.CompletedTask;
    }
}

将政策添加到 startup.cs

services.AddAuthorization(options =>
{
    options.AddPolicy("View", policy => policy.Requirements.Add(new RolesRequirement("View")));
    options.AddPolicy("ConfirmAlarm", policy => policy.Requirements.Add(new RolesRequirement("ConfirmAlarm")));
    options.AddPolicy("ObjectEditor", policy => policy.Requirements.Add(new RolesRequirement("ObjectEditor")));
});

并在控制器方法之前添加属性。

[Authorize(Policy = "View")]
[Authorize(Policy = "ObjectEditor")]
[HttpPost("[action]")]
public async Task<string> SomeAction()
{
   //...some code
}

请尝试以下行:

ClaimsIdentity id = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme,
            ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);

而不是:

ClaimsIdentity id = new ClaimsIdentity(claims, "ApplicationCookie", 
            ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);

CookieAuthenticationDefaults.AuthenticationSchemeCookies ,它匹配 Startup.cs:

中 cookie 的默认 authenticationScheme
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  .AddCookie();

更新:

您可以手动检查声明:

services.AddAuthorization(options =>
{
    options.AddPolicy("AllowedView", policy =>
    {
        policy.RequireAssertion(context =>
        {

            var roles = context.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Role)?.Value;

            var  listRolesElements = roles.Split(',').ToList();


            return listRolesElements.Contains("View");
        });
    });
});

并在需要View权限的控制器上应用策略:

[Authorize(Policy = "AllowedView")]