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

ASP.NET API授权过滤器通用权限校验逻辑实现咨询

通用权限校验实现方案

核心思路

把AccessToken中的Condition表达式转换成可复用的校验逻辑,分两步处理:

  • 优先尝试从**请求上下文(路由/Query参数)**直接校验,避免不必要的数据库查询
  • 若无法从上下文完成校验,则查询目标实体后用表达式验证

实现步骤

1. 依赖准备(可选但推荐)

使用System.Linq.Dynamic.Core库解析Condition表达式,省去手动编写复杂解析逻辑的成本。通过NuGet安装:

Install-Package System.Linq.Dynamic.Core

2. 通用表达式校验工具类

封装表达式解析、请求参数校验判断、临时实体校验等通用逻辑:

using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Reflection;

public static class ConditionValidator
{
    // 将字符串Condition转换为可执行的实体校验Lambda表达式
    public static Expression<Func<T, bool>> GetValidationExpression<T>(string condition)
    {
        // 统一表达式关键字大小写,避免大小写不兼容问题
        var normalizedCondition = condition.Replace("EQ", "eq").Replace("IN", "in");
        return DynamicExpressionParser.ParseLambda<T, bool>(null, normalizedCondition);
    }

    // 判断当前条件是否能通过请求参数直接校验
    public static bool CanValidateFromRequest<T>(string condition, HttpContext context)
    {
        var propertyName = ExtractTargetProperty(condition);
        if (string.IsNullOrEmpty(propertyName))
            return false;

        // 检查路由或Query参数中是否存在对应属性的参数
        return context.Request.RouteValues.ContainsKey(propertyName) 
               || context.Request.Query.ContainsKey(propertyName);
    }

    // 从条件字符串中提取目标属性名(适配EQ/IN场景,可根据需求扩展)
    private static string ExtractTargetProperty(string condition)
    {
        var lowerCondition = condition.ToLower();
        if (lowerCondition.Contains("eq"))
            return lowerCondition.Split("eq")[0].Trim();
        if (lowerCondition.Contains("in"))
            return lowerCondition.Split("in")[0].Trim();
        return null;
    }

    // 从请求上下文提取参数并完成校验
    public static bool ValidateFromRequest<T>(string condition, HttpContext context)
    {
        var propertyName = ExtractTargetProperty(condition);
        if (string.IsNullOrEmpty(propertyName))
            return false;

        // 获取参数值
        string paramValue = null;
        if (context.Request.RouteValues.TryGetValue(propertyName, out var routeValue))
            paramValue = routeValue.ToString();
        else if (context.Request.Query.TryGetValue(propertyName, out var queryValue))
            paramValue = queryValue.ToString();

        // 构造临时实体并赋值,用表达式校验
        var tempEntity = Activator.CreateInstance<T>();
        var property = typeof(T).GetProperty(propertyName);
        if (property == null || paramValue == null)
            return false;

        var convertedValue = Convert.ChangeType(paramValue, property.PropertyType);
        property.SetValue(tempEntity, convertedValue);

        var validator = GetValidationExpression<T>(condition).Compile();
        return validator(tempEntity);
    }
}

3. 实现Authorization Filter

在过滤器中整合两种校验场景的逻辑:

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.EntityFrameworkCore;

public class StudentAuthorizationFilter : IAsyncAuthorizationFilter
{
    private readonly YourDbContext _dbContext; // 替换为你的DbContext类型

    public StudentAuthorizationFilter(YourDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        // 1. 获取AccessToken中的Condition(替换为你实际的Token解析逻辑)
        var accessToken = ParseAccessTokenFromRequest(context.HttpContext);
        if (string.IsNullOrEmpty(accessToken?.Condition))
        {
            context.Result = new Microsoft.AspNetCore.Mvc.ForbidResult();
            return;
        }

        // 2. 尝试从请求上下文直接校验
        if (ConditionValidator.CanValidateFromRequest<Student>(accessToken.Condition, context.HttpContext))
        {
            var isValid = ConditionValidator.ValidateFromRequest<Student>(accessToken.Condition, context.HttpContext);
            if (!isValid)
                context.Result = new Microsoft.AspNetCore.Mvc.ForbidResult();
            return;
        }

        // 3. 无法从上下文校验,查询数据库实体后验证
        var studentIdStr = context.Request.RouteValues["StudentId"]?.ToString();
        if (!int.TryParse(studentIdStr, out var studentId))
        {
            context.Result = new Microsoft.AspNetCore.Mvc.BadRequestResult();
            return;
        }

        var student = await _dbContext.Students.FirstOrDefaultAsync(s => s.Id == studentId);
        if (student == null)
        {
            context.Result = new Microsoft.AspNetCore.Mvc.NotFoundResult();
            return;
        }

        var validator = ConditionValidator.GetValidationExpression<Student>(accessToken.Condition).Compile();
        if (!validator(student))
            context.Result = new Microsoft.AspNetCore.Mvc.ForbidResult();
    }

    // 替换为你实际的AccessToken解析逻辑
    private accessToken ParseAccessTokenFromRequest(HttpContext context)
    {
        // 示例:从请求头获取并解析Token
        var authHeader = context.Request.Headers["Authorization"].FirstOrDefault()?.Replace("Bearer ", "");
        // 此处省略Token解析为accessToken对象的逻辑,直接模拟返回
        return new accessToken { Condition = context.Request.Headers["Condition"].FirstOrDefault() };
    }
}

4. 注册过滤器

在Program.cs中注入DbContext并注册过滤器:

builder.Services.AddDbContext<YourDbContext>(options => 
    options.UseSqlServer(builder.Configuration.GetConnectionString("YourDbConn")));

// 全局注册过滤器,或针对特定Controller/Action单独注册
builder.Services.AddControllers(options =>
{
    options.Filters.Add<StudentAuthorizationFilter>();
});

注意事项

  • 表达式容错性:如果Condition包含复杂多条件组合,需要优化ExtractTargetProperty方法,或引入更专业的表达式解析逻辑
  • 性能优化:高频接口可缓存解析后的Lambda表达式,避免重复解析开销
  • 安全性:确保Condition表达式来源可信,避免注入风险(限制表达式仅允许预定义的属性和操作符)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 01:36:34