.NET Core 2.2 WebAPI:如何通过授权过滤控制器返回的集合子集?
刚好做过类似的场景,给你一步步拆解怎么实现这个需求——在.NET Core 2.2 WebAPI里,我们可以通过自定义授权逻辑把用户的权限转化为查询过滤器,确保控制器只返回用户有权限查看的Bar子集。
具体实现步骤
1. 定义自定义授权需求类
首先创建一个授权需求类,用来承载后续要传递的权限过滤信息:
public class BarAuthorizationRequirement : IAuthorizationRequirement { // 存储用户允许访问的Bar ID集合,供控制器后续使用 public List<int> AllowedBarIds { get; set; } = new List<int>(); }
2. 实现自定义AuthorizationHandler
接下来写核心的授权处理逻辑,从Bearer令牌的声明里解析出用户能访问的Bar ID,然后填充到需求类的集合中。这里假设你的令牌里有一个名为allowed_bar_ids的声明,值是逗号分隔的ID字符串(比如"1,2,3"):
public class BarAuthorizationHandler : AuthorizationHandler<BarAuthorizationRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BarAuthorizationRequirement requirement) { // 从用户身份声明中获取权限信息 var allowedIdsClaim = context.User.FindFirst("allowed_bar_ids"); if (allowedIdsClaim == null) { // 没有权限声明,直接标记授权失败 context.Fail(); return Task.CompletedTask; } // 把声明值解析为整数ID集合 var allowedIds = allowedIdsClaim.Value.Split(',') .Select(int.Parse) .ToList(); // 将允许的ID集合存入需求对象,方便控制器获取 requirement.AllowedBarIds = allowedIds; // 标记授权通过(我们的目标是获取过滤条件,而非直接拒绝请求) context.Succeed(requirement); return Task.CompletedTask; } }
3. 在Startup中配置授权服务
在ConfigureServices方法里注册身份验证和自定义授权逻辑:
public void ConfigureServices(IServiceCollection services) { // 配置Bearer令牌验证 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "你的Issuer", ValidAudience = "你的Audience", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("你的签名密钥")) }; }); // 添加自定义授权策略 services.AddAuthorization(options => { options.AddPolicy("BarAccessPolicy", policy => policy.Requirements.Add(new BarAuthorizationRequirement())); }); // 注册自定义授权Handler到DI容器 services.AddScoped<IAuthorizationHandler, BarAuthorizationHandler>(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
4. 在Foo控制器中应用过滤条件
最后在控制器里,通过IAuthorizationService触发授权流程,拿到允许的Bar ID集合,再用这个集合过滤数据源:
[Route("foo")] [ApiController] public class FooController : ControllerBase { private readonly IAuthorizationService _authorizationService; private readonly IBarRepository _barRepository; // 假设这是你的Bar数据访问服务 public FooController(IAuthorizationService authorizationService, IBarRepository barRepository) { _authorizationService = authorizationService; _barRepository = barRepository; } [HttpGet("bars")] [Authorize(Policy = "BarAccessPolicy")] public async Task<IActionResult> GetBars() { var requirement = new BarAuthorizationRequirement(); var authResult = await _authorizationService.AuthorizeAsync(User, requirement); if (!authResult.Succeeded) { return Forbid(); } // 获取过滤用的Bar ID集合 var allowedBarIds = requirement.AllowedBarIds; // 应用过滤器,只返回用户有权限查看的Bar var filteredBars = await _barRepository.GetBarsAsync(bar => allowedBarIds.Contains(bar.Id)); return Ok(filteredBars); } }
优化小技巧
如果你觉得在控制器里创建需求对象有点繁琐,可以改用HttpContext.Items来传递过滤条件:
在BarAuthorizationHandler的HandleRequirementAsync方法里,添加一行:
context.HttpContext.Items["AllowedBarIds"] = allowedIds;
然后在控制器里直接获取:
var allowedBarIds = HttpContext.Items["AllowedBarIds"] as List<int>;
这样代码会更简洁。
内容的提问来源于stack exchange,提问作者Michael M
相关产品推荐
相关产品推荐

