.NET Core 2.1 MVC Identity Authorization - 不同部分的不同用户角色

.NET Core 2.1 MVC Identity Authorization - Different user roles for different parts

目前,我正在一个项目管理网站上工作。系统中有一个SuperAdmin(角色),可以创建新项目。超级管理员可以将用户分配给具有不同角色的这些项目,例如管理员或观察员。一个用户可以为不同的项目担任不同的角色,甚至根本不担任任何角色。
例如:

  1. 用户 A 是项目 A 的管理员
  2. 用户 A 是项目 B 的观察员(只读)
  3. 用户 A 没有项目 C 的角色(无法访问该项目)
  4. 用户 B 是项目 B 的管理员
  5. 用户 B 是项目 C 的观察员(仅限读取权限)

Identity 似乎不支持这种行为。基于声明的授权似乎支持静态声明,但不支持动态声明(使用 id 访问项目)。 我可以创建自己的 UserProjectRoles class 来关联用户、项目和角色,并在授权处理程序(基于策略的授权)中使用它,但我想知道这是否是正确的解决方案。你会如何解决这个任务?

编辑:

我最终执行了以下操作:我创建了一个新的 UserProjectClaims table,它连接了用户和项目,并将角色类型包含为枚举(我将把 role/claim 类型移动到它是自己的 table,这只是为了测试)。

public class UserProjectClaim
{
    public int ProjectId { get; set; }
    public Project Project { get; set; }

    public int UserId { get; set; }
    public AppUser User { get; set; }

    public UserProjectClaimEnum ClaimType { get; set; }
}

然后我在基于策略的授权教程中看到的 AuthorizationHandler 中使用了这个 table:

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ProjectAdminRequirement requirement)
{
    if (context.Resource is AuthorizationFilterContext authContext)
    {
        var projectId = Int32.Parse(authContext.HttpContext.Request.Query["projectId"]);
        var userid = (await _userManager.GetUserAsync(context.User)).Id;
        var claim = _dbContext.AppUsers.Include(i=>i.UserProjectClaims).Single(u=>u.Id==userid).UserProjectClaims.SingleOrDefault(p => p.ProjectId == projectId);      

        if (claim != null && claim.ClaimType == Data.Enums.UserProjectClaimEnum.ProjectAdmin)
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }
    }           
}

它按预期工作。

使用个人用户帐户 (VS2017) 创建新的 Web 应用程序 (MVC) 后,您会发现 tables 作为 Entity Framework 核心的一部分,例如 AspNetRoles、AspNetRoleClaims、AspNetUserRoles、AspNetUserClaims IdentityContext.

AccountController 已注入 UserManager,但没有维护角色和声明的方法。未提供开箱即用的视图(页面)、控制器和模型来管理关系。

好消息是 UserManager 具有为用户添加声明和角色的各种功能。 AddClaimAsync、AddToRoleAsync、GetClaimsAsync、GetRolesAsync、GetUsersForClaimAsync、GetUsersInRoleAsync、RemoveClaimAsync、RemoveFromRoleAsync 和将 claims/roles 作为 IEnumerable 处理的版本。

短期解决方案:向 AccountController 或 ManageController 添加方法,甚至创建 RolesController 来支持管理这些关系的页面应该不是一项艰巨的任务。

长期解决方案:了解如何在创建新的 MVC Identity 项目时添加模板以生成这些项目。然后通过在 GitHub 中制作 public 来炫耀 :) 或者写一篇文章,介绍您从处于您处境的其他人那里学到了什么。

后记:通过创建一个放在请求处理路径中的小中间件,您可以为当前用户加载roles/claims,其余的请求处理可以参考。从项目到角色的联接 table 可能具有读取角色和写入角色,您可以将所需的角色与用户拥有的 roles/claims 进行比较。

技术: 是对自定义策略和授权的精彩解释。在您的情况下,该策略将测试用户是否具有与您的项目匹配的 role/claim。您上面的角色实际上是项目读取、项目写入。如果两者都没有,则无法访问。