ASP .NET MVC Identity 用户多个组,多个角色

时间:2021-06-25 03:42:40

标签: asp.net-mvc asp.net-core asp.net-identity

我希望创建一个 ASP.NET Core 5 Identity 解决方案,用户可以在其中创建组。 创建者成为该组的管理员,并且可以将其他用户 Crud 到该组 - (然后其他用户可能成为该组的管理员)。 创建者还需要存在于其他组中,无论是否有管理员。 是否有一种简单的方法可以在 Identity 中使用角色作为具有策略/声明的组来执行此操作,或者是否需要一些新表?像这样 https://www.codeproject.com/Tips/5276188/Implementing-User-Groups-using-Claims-in-ASP-NET-I?fid=1962554&df=90&mpp=25&sort=Position&view=Normal&spc=Relaxed&prof=True

1 个答案:

答案 0 :(得分:0)

使用声明本身就足以进行授权(例如,此用户是管理员,他能否将其他用户提升为管理员状态)。但是使用声明将您限制为字符串类型,它可以采用任意值。这给您带来了确保每个值都符合预期的负担。

要拥有更健全的数据库架构,您应该将成员资格存储在单独的表中。这意味着在用户和组之间创建多对多关系来存储成员资格,这将需要一个查找表,但是看到您如何使用 ASP.NET Core 5 和 EF Core 5,它会为您创建此表.

但您可能需要存储何时以及由谁将用户添加到组中。这意味着在查找表上存储一些数据。因此,如果您需要这些,您也应该为该查找表创建一个实体。

至于代码,这里是您的起点:

public record Group(string Name)
{
    public const string AdminClaimName = "group_admin";
    public Guid Id { get; init; } = Guid.Empty;
    public List<IdentityUser> Members { get; set; } = new List<IdentityUser>();
}

[ApiController]
public class UserGroupController : ControllerBase
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly ApplicationDbContext _db;

    public UserGroupController(UserManager<IdentityUser> userManager, ApplicationDbContext db)
    {
        _userManager = userManager;
        _db = db;
    }

    public record GroupCreateRequest(string GroupName);

    [HttpPost]
    public async Task<IActionResult> CreateGroup(GroupCreateRequest request,
                                                 CancellationToken cancellationToken = default)
    {
        var user = await _userManager.GetUserAsync(User);
        
        var group = new Group(request.GroupName);
        await _db.Set<Group>().AddAsync(group, cancellationToken);
        await _db.SaveChangesAsync(cancellationToken);
        await _userManager.AddClaimAsync(user, new Claim(type: Group.AdminClaimName, value: group.Id.ToString()));

        return Ok(group);
    }

    public record GroupMembershipRequest(string MemberUserId);

    [HttpPost("{id:guid}/membership")]
    public async Task<IActionResult> AddUserToGroup(Guid groupId,
                                     GroupMembershipRequest request,
                                     CancellationToken cancellationToken = default)
    {
        var user = await _userManager.GetUserAsync(User);
        var claims = await _userManager.GetClaimsAsync(user);

        // check if the current user is the admin of that group
        if (claims.Any(c => c.Type == Group.AdminClaimName && c.Value == groupId.ToString()))
        {
            return Forbid();
        }

        var member = await _userManager.FindByIdAsync(request.MemberUserId);
        var group = await _db.Set<Group>().FindAsync(groupId);
        group.Members.Add(member);
        await _db.SaveChangesAsync(cancellationToken);

        return NoContent();
    }


    public record UserPromotionRequest(Guid GroupId, string MemberUserId);

    [HttpPost("promote")]
    public async Task<IActionResult> PromoteUserToAdmin(UserPromotionRequest request,
                                                        CancellationToken cancellationToken = default)
    {
        var user = await _userManager.GetUserAsync(User);
        var claims = await _userManager.GetClaimsAsync(user);

        // check if the current user is the admin of that group
        if (claims.Any(c => c.Type == Group.AdminClaimName && c.Value == request.GroupId.ToString()))
        {
            return Forbid();
        }

        var member = await _userManager.FindByIdAsync(request.MemberUserId);
        var group = await _db.Set<Group>().FindAsync(request.GroupId);
        await _userManager.AddClaimAsync(member, new Claim(type: Group.AdminClaimName, value: group.Id.ToString()));
        return NoContent();
    }
}

(我省略了一些验证和空检查,您需要自己添加。)

注意控制器(当前登录的用户)的 User 属性和从数据库中获取的 user 实例之间的区别。

相关问题