Asp.Net Core Web API 5.0与Angular自定义角色授权实现咨询
实现角色授权校验的方案
你可以直接用ASP.NET Core自带的自定义授权中间件+自定义属性的方案实现,完全不需要依赖Asp.Net Identity,具体步骤如下:
步骤1:定义角色校验标注属性
先定义一个自定义属性,用来标记哪些控制器/动作方法需要做角色校验、以及需要的角色权限:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class RequiresRoleAttribute : Attribute { // 允许传入多个要求的角色,用户拥有任意一个即可访问 public string[] RequiredRoles { get; } public RequiresRoleAttribute(params string[] requiredRoles) { RequiredRoles = requiredRoles; } }
步骤2:实现全局授权中间件
中间件会在所有请求进入控制器之前统一处理鉴权逻辑,不用在每个动作方法里重复写校验代码:
public class CustomRoleAuthMiddleware { private readonly RequestDelegate _next; public CustomRoleAuthMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context, YourDbContext dbContext, IDistributedCache cache) { // 获取当前请求对应的终点元数据 var endpoint = context.GetEndpoint(); if (endpoint == null) { await _next(context); return; } // 检查当前请求的控制器/动作是否需要角色校验 var roleAuthAttr = endpoint.Metadata.GetMetadata<RequiresRoleAttribute>(); if (roleAuthAttr == null) { // 无校验要求直接放行 await _next(context); return; } // 从请求头取前端传递的UserID,Header名可以和前端自行约定 if (!context.Request.Headers.TryGetValue("X-User-ID", out var userIdStr) || !Guid.TryParse(userIdStr, out var userId)) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; return; } // 先查缓存获取用户角色,避免频繁查库 var cacheKey = $"user_roles_{userId}"; var cachedRoles = await cache.GetStringAsync(cacheKey); List<string> userRoles; if (!string.IsNullOrEmpty(cachedRoles)) { userRoles = JsonSerializer.Deserialize<List<string>>(cachedRoles); } else { // 缓存不存在时从存量UserRole表查询用户所有角色 userRoles = await dbContext.UserRoles .Where(ur => ur.UserId == userId) .Select(ur => ur.RoleName) .ToListAsync(); // 查询结果写入缓存,过期时间可根据业务调整,比如15分钟 await cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(userRoles), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15) }); } // 校验用户是否拥有要求的角色 if (!roleAuthAttr.RequiredRoles.Intersect(userRoles).Any()) { context.Response.StatusCode = StatusCodes.Status403Forbidden; return; } // 校验通过放行 await _next(context); } }
步骤3:注册中间件到请求管道
在Program.cs中注册中间件,注意要放在路由匹配之后、控制器执行之前:
// 其他服务注册、中间件配置省略 app.UseRouting(); // 注册自定义角色授权中间件 app.UseMiddleware<CustomRoleAuthMiddleware>(); app.MapControllers(); // 其他配置省略
步骤4:给需要鉴权的接口加标注
// 作用在控制器上,整个控制器所有接口都需要Admin角色 [RequiresRole("Admin")] public class SystemConfigController : ControllerBase { // 作用在单独动作上,覆盖控制器的配置,支持同时指定多个角色 [RequiresRole("Admin", "Auditor")] public IActionResult GetAuditLogs() { return Ok(); } }
关于是否需要每个动作都查库的问题
完全不需要在每个动作方法里单独查询数据库:
- 中间件已经统一处理了全局所有请求的角色校验逻辑,业务代码里不需要再重复写鉴权代码
- 配合缓存机制可以大幅降低数据库查询压力,只有缓存过期、或者用户角色变动时才需要重新查询数据库。如果用户角色发生变更,你只需要在修改角色的业务逻辑里删除对应用户的角色缓存即可。
内容的提问来源于stack exchange,提问作者Dibyo Chatterjee
相关产品推荐
相关产品推荐

