You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ASP.NET Identity适配可自定义权限组的现有数据库模型?

Hey there! Let's work through how to adapt your custom permission model to ASP.NET Identity while sticking to your requirements and best practices.

First, let's clarify a quick point about Claims: while MSDN notes Claims are about identifying a principal, they absolutely can represent permissions too—permissions are just a type of attribute that describes what the principal is allowed to do. So we can use Claims here, just in a structured way that aligns with your fixed permission enum.

Core Approach

We'll build a system that:

  • Uses a fixed enum for your AccessItem (to enforce only trusted permission IDs)
  • Lets admins create custom AccessGroup collections of these permissions
  • Aggregates a user's permissions from their assigned AccessGroups at login
  • Integrates with ASP.NET Core's authorization system for declarative checks
Step-by-Step Implementation

1. Define Your Permission Enum

First, lock down your trusted AccessItem values as a strong-type enum. This ensures no arbitrary permissions can be added:

public enum Permission
{
    CanDeleteSale,
    CanCreateCustomer,
    CanViewReports,
    // Add all your fixed permission IDs here
}

2. Extend Identity Entities for Access Groups

Create the entities to map your User-AccessGroup-Permission relationships. We'll use many-to-many relationships to keep things flexible:

// AccessGroup: Admin-defined collection of permissions
public class AccessGroup
{
    public int Id { get; set; }
    public string Name { get; set; } // e.g., "Sales Managers", "Customer Support"
    
    // Link to permissions via join table
    public ICollection<AccessGroupPermission> AccessGroupPermissions { get; set; } = new List<AccessGroupPermission>();
    
    // Link to users via join table
    public ICollection<UserAccessGroup> UserAccessGroups { get; set; } = new List<UserAccessGroup>();
}

// Join table: AccessGroup <-> Permission
public class AccessGroupPermission
{
    public int AccessGroupId { get; set; }
    public AccessGroup AccessGroup { get; set; }
    
    public Permission Permission { get; set; }
}

// Join table: User <-> AccessGroup
public class UserAccessGroup
{
    public string UserId { get; set; }
    public ApplicationUser User { get; set; }
    
    public int AccessGroupId { get; set; }
    public AccessGroup AccessGroup { get; set; }
}

Don't forget to add these DbSets to your ApplicationDbContext and configure the relationships in OnModelCreating.

3. Auto-Load Permissions into Claims at Login

We'll use a custom UserClaimsPrincipalFactory to automatically fetch a user's permissions from their AccessGroups and add them to their ClaimsIdentity when they log in. This way, permissions are always available for authorization checks:

public class CustomUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
    private readonly ApplicationDbContext _dbContext;

    public CustomUserClaimsPrincipalFactory(
        UserManager<ApplicationUser> userManager,
        IOptions<IdentityOptions> optionsAccessor,
        ApplicationDbContext dbContext)
        : base(userManager, optionsAccessor)
    {
        _dbContext = dbContext;
    }

    public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
    {
        // Start with the default claims (like email, name)
        var principal = await base.CreateAsync(user);

        // Fetch all unique permissions from the user's AccessGroups
        var userPermissions = await _dbContext.UserAccessGroups
            .Where(uag => uag.UserId == user.Id)
            .SelectMany(uag => uag.AccessGroup.AccessGroupPermissions)
            .Select(agp => agp.Permission)
            .Distinct()
            .ToListAsync();

        // Add each permission as a Claim with a consistent type
        var identity = (ClaimsIdentity)principal.Identity;
        foreach (var permission in userPermissions)
        {
            identity.AddClaim(new Claim("Permission", permission.ToString()));
        }

        return principal;
    }
}

Register this factory in your Program.cs/Startup.cs:

services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, CustomUserClaimsPrincipalFactory>();

4. Set Up Declarative Authorization Policies

Next, we'll create authorization policies for each permission in your enum. This lets you use the [Authorize] attribute with policy names tied directly to your enum values:

services.AddAuthorization(options =>
{
    // Auto-create a policy for every permission in the enum
    foreach (Permission permission in Enum.GetValues(typeof(Permission)))
    {
        var permissionName = permission.ToString();
        options.AddPolicy(permissionName, policy =>
            policy.RequireClaim("Permission", permissionName));
    }
});

5. Use Declarative Authorization in Your App

Now you can secure controllers or actions with your permission policies, just like you would with roles:

[Authorize(Policy = nameof(Permission.CanDeleteSale))]
public IActionResult DeleteSale(int saleId)
{
    // Your delete logic here
    return RedirectToAction(nameof(Index));
}
Key Benefits of This Approach
  • Admin Flexibility: Admins can create any combination of AccessGroups using your fixed permission set
  • Type Safety: The enum ensures only trusted permissions are used, no arbitrary strings
  • Seamless Identity Integration: Uses ASP.NET Identity's built-in Claims system, so you don't have to reinvent the wheel for authentication/authorization
  • Declarative Checks: Keeps your authorization logic clean and visible right in your controllers/actions

内容的提问来源于stack exchange,提问作者Vinicius Gonçalves

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:45:26