ASP.Net Web API如何基于[FromRoute]参数值实现用户授权?
基于路由参数{group}的ASP.NET Core授权实现方案
针对你需要基于路由{group}参数实现用户授权的需求,以下是一套可落地的解决方案,完全适配自定义特性要求,且在基础[Authorize]特性之上生效:
核心思路
通过自定义授权策略+授权处理程序实现路由参数的权限校验,同时结合动作过滤器处理group不存在的404场景,整体流程如下:
- 定义授权需求与处理程序,从路由中提取
group参数,校验用户权限与group存在性 - 封装自定义授权特性,绑定到上述策略
- 注册授权服务与全局过滤器,处理404返回
- 在控制器方法上直接使用自定义特性
具体实现步骤
1. 定义授权需求与处理程序
首先创建授权需求标识类,以及核心的授权处理程序,负责提取路由参数、校验权限与group存在性:
// 授权需求标识类(仅作为策略绑定标识) public class GroupAuthorizationRequirement : IAuthorizationRequirement { } // 授权处理程序核心逻辑 public class GroupAuthorizationHandler : AuthorizationHandler<GroupAuthorizationRequirement> { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IGroupService _groupService; // 替换为你实际的Group管理服务 public GroupAuthorizationHandler(IHttpContextAccessor httpContextAccessor, IGroupService groupService) { _httpContextAccessor = httpContextAccessor; _groupService = groupService; } protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, GroupAuthorizationRequirement requirement) { var httpContext = _httpContextAccessor.HttpContext; // 从路由集合中提取group参数 if (!httpContext.Request.RouteValues.TryGetValue("group", out var groupValue) || string.IsNullOrEmpty(groupValue?.ToString())) { context.Fail(); return; } var groupName = groupValue.ToString(); // 校验group是否存在,不存在则标记后续返回404 var groupExists = await _groupService.DoesGroupExistAsync(groupName); if (!groupExists) { httpContext.Items["GroupNotFound"] = true; context.Fail(); return; } // 校验当前用户是否有权限访问该group var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier); var hasAccess = await _groupService.DoesUserHaveAccessToGroupAsync(userId, groupName); if (hasAccess) context.Succeed(requirement); else context.Fail(); } }
2. 封装自定义授权特性
创建继承自AuthorizeAttribute的自定义特性,直接绑定到我们的授权策略,自动继承基础[Authorize]的登录校验功能:
public class GroupAuthorizeAttribute : AuthorizeAttribute { public GroupAuthorizeAttribute() : base("GroupAuthorization") { } }
3. 注册授权服务与全局过滤器
在Program.cs中注册授权策略、处理程序,以及用于返回404的全局动作过滤器:
// 注册自定义授权策略 builder.Services.AddAuthorization(options => { options.AddPolicy("GroupAuthorization", policy => { policy.Requirements.Add(new GroupAuthorizationRequirement()); }); }); // 注册授权处理程序与依赖服务 builder.Services.AddScoped<IAuthorizationHandler, GroupAuthorizationHandler>(); builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped<IGroupService, GroupService>(); // 替换为你的Group服务实现 // 注册全局过滤器,处理group不存在的404场景 builder.Services.AddControllers(options => { options.Filters.Add<GroupNotFoundFilter>(); }); // 全局过滤器实现 public class GroupNotFoundFilter : IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { if (context.HttpContext.Items.TryGetValue("GroupNotFound", out var value) && (bool)value) { context.Result = new NotFoundResult(); return; } await next(); } }
4. 在控制器中使用自定义特性
直接在需要授权的控制器方法上添加[GroupAuthorize]特性,结合基础的[Authorize]确保用户已登录:
[ApiController] [Route("foo/{group}")] [Authorize] // 确保用户已通过身份验证 public class FooController : ControllerBase { private readonly IGroupService _groupService; public FooController(IGroupService groupService) { _groupService = groupService; } [HttpGet("settings")] [GroupAuthorize] public async Task<IActionResult> GetGroupSettings(string group) { var settings = await _groupService.GetGroupSettingsAsync(group); return Ok(settings); } [HttpGet("users")] [GroupAuthorize] public async Task<IActionResult> GetGroupUsers(string group) { var users = await _groupService.GetGroupUsersAsync(group); return Ok(users); } }
效果说明
- 用户未登录:触发
[Authorize]的401返回 - 用户已登录但无对应group权限:授权处理程序返回401
- 请求的
group不存在:全局过滤器捕获标记,返回404 - 用户有权限且group存在:正常执行控制器方法
内容的提问来源于stack exchange,提问作者Russel Bryan Marco
相关产品推荐
相关产品推荐

