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

如何在ASP.NET Core 8中基于Responsibilities实体实现自定义授权

基于自定义Responsibilities实体实现ASP.NET Core 8.0授权

核心实现方案

要基于数据库中的Responsibilities实体实现动态授权,最佳方式是自定义授权需求(IAuthorizationRequirement)和处理程序(AuthorizationHandler),通过EF Core查询数据库验证用户权限。这种方式完全替代默认角色/策略逻辑,支持数据库驱动的权限配置,同时兼容[Authorize(Policy = "...")]特性或自定义特性。

步骤1:定义实体与数据上下文(示例结构)

先确认Responsibilities实体及用户-职责关联关系(多对多场景),示例代码如下:

// 职责实体
public class Responsibility
{
    public int Id { get; set; }
    public string Name { get; set; } // 职责标识,如"ManageOrders"、"ViewReports"
    // 可扩展字段:描述、启用状态等
}

// 用户-职责关联表
public class UserResponsibility
{
    public string UserId { get; set; } // 关联用户ID(对应Identity/JWT的用户标识)
    public int ResponsibilityId { get; set; }

    public ApplicationUser User { get; set; }
    public Responsibility Responsibility { get; set; }
}

// 数据上下文
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<Responsibility> Responsibilities { get; set; }
    public DbSet<UserResponsibility> UserResponsibilities { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 配置多对多主键
        modelBuilder.Entity<UserResponsibility>()
            .HasKey(ur => new { ur.UserId, ur.ResponsibilityId });
    }
}

步骤2:创建自定义授权需求

定义需求类,用于传递需要检查的职责名称:

public class ResponsibilityRequirement : IAuthorizationRequirement
{
    public string ResponsibilityName { get; }

    public ResponsibilityRequirement(string responsibilityName)
    {
        ResponsibilityName = responsibilityName ?? throw new ArgumentNullException(nameof(responsibilityName));
    }
}

步骤3:实现授权处理程序

创建处理程序,注入AppDbContext查询数据库,验证当前用户是否拥有指定职责:

public class ResponsibilityHandler : AuthorizationHandler<ResponsibilityRequirement>
{
    private readonly AppDbContext _dbContext;

    public ResponsibilityHandler(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ResponsibilityRequirement requirement)
    {
        // 获取当前用户ID(根据认证方式调整:Identity取ClaimTypes.NameIdentifier,JWT取对应Claim)
        var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
        if (string.IsNullOrEmpty(userId))
        {
            context.Fail();
            return;
        }

        // 数据库验证:用户是否拥有指定职责
        var hasPermission = await _dbContext.UserResponsibilities
            .AnyAsync(ur => ur.UserId == userId && 
                            ur.Responsibility.Name == requirement.ResponsibilityName);

        if (hasPermission)
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }
    }
}

步骤4:配置授权服务(Program.cs)

在AddAuthorization中注册处理程序,并预定义策略(方便直接用[Authorize(Policy = "...")]):

var builder = WebApplication.CreateBuilder(args);

// 注册DbContext(已有则跳过)
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

// 配置授权策略
builder.Services.AddAuthorization(options =>
{
    // 预定义策略:策略名称与职责名称一一对应
    options.AddPolicy("ManageOrders", policy =>
        policy.Requirements.Add(new ResponsibilityRequirement("ManageOrders")));

    options.AddPolicy("ViewReports", policy =>
        policy.Requirements.Add(new ResponsibilityRequirement("ViewReports")));
});

// 注册授权处理程序
builder.Services.AddScoped<IAuthorizationHandler, ResponsibilityHandler>();

// 其他服务注册(认证、控制器等,保留原有配置)
builder.Services.AddControllers();
// ...(如AddIdentity/AddJwtBearer等认证配置)

var app = builder.Build();

// 中间件配置(保留原有顺序)
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

步骤5:在端点/控制器中使用

方式1:使用预定义策略

直接在控制器或Action上标记特性:

[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
    // 仅允许拥有"ManageOrders"职责的用户访问
    [Authorize(Policy = "ManageOrders")]
    [HttpPost]
    public IActionResult CreateOrder(OrderDto dto)
    {
        // 业务逻辑
        return Ok();
    }

    // 仅允许拥有"ViewReports"职责的用户访问
    [Authorize(Policy = "ViewReports")]
    [HttpGet("reports")]
    public IActionResult GetOrderReports()
    {
        // 业务逻辑
        return Ok();
    }
}

方式2:自定义授权特性(可选)

如果想简化写法,可自定义特性:

public class AuthorizeResponsibilityAttribute : AuthorizeAttribute
{
    public AuthorizeResponsibilityAttribute(string responsibilityName)
    {
        Policy = responsibilityName;
    }
}

使用时更简洁:

[AuthorizeResponsibility("ManageOrders")]
[HttpPost]
public IActionResult CreateOrder(OrderDto dto)
{
    // 业务逻辑
    return Ok();
}

注:若职责是动态新增的,可实现IAuthorizationPolicyProvider从数据库自动生成策略,无需手动配置。

优化建议

  1. 权限缓存:避免每次请求查询数据库,可在用户登录时加载职责到缓存(内存/Redis),或在处理程序中加入缓存逻辑。
  2. 多职责验证:扩展处理程序支持同时检查多个职责(如RequireAllRequirements)。
  3. 动态策略加载:实现IAuthorizationPolicyProvider从数据库读取所有职责,自动生成对应策略。

内容的提问来源于stack exchange,提问作者MHz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 18:42:37