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

ASP.NET Core 8 Web API如何基于用户权限实现条件序列化?

ASP.NET Core 8 按用户套餐(Claims)统一过滤响应字段的方案

下面提供几种在ASP.NET Core 8中统一处理所有控制器响应、根据用户Claims移除指定字段的可行方案:

方案一:自定义ActionFilter全局过滤

通过创建全局Action过滤器,在响应返回前拦截并根据用户套餐Claims修改输出内容,这种方式直观易维护,适合大多数场景。

1. 实现自定义过滤器及配套Json转换器

using Microsoft.AspNetCore.Mvc.Filters;
using System.Reflection;
using System.Text.Json;

// 全局响应字段过滤过滤器
public class FilterFieldsByPlanAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is ObjectResult objectResult && objectResult.Value != null)
        {
            var user = context.HttpContext.User;
            // 从Claims中获取用户套餐标识
            var userPlan = user.FindFirstValue("UserPlan");
            if (string.IsNullOrEmpty(userPlan)) return;

            // 定义套餐与需移除字段的映射规则
            var fieldRules = new Dictionary<string, List<string>>
            {
                { "Basic", new List<string> { "PremiumFeature", "AdvancedAnalytics" } },
                { "Pro", new List<string> { "EnterpriseSupport" } }
            };

            if (fieldRules.TryGetValue(userPlan, out var fieldsToRemove))
            {
                // 使用自定义Json转换器序列化,避免修改原对象
                var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
                options.Converters.Add(new PlanBasedPropertyConverter(userPlan, fieldRules));
                
                var filteredJson = JsonSerializer.Serialize(objectResult.Value, options);
                var filteredValue = JsonSerializer.Deserialize(filteredJson, objectResult.Value.GetType(), options);
                objectResult.Value = filteredValue;
            }
        }
        base.OnResultExecuting(context);
    }
}

// 基于套餐的Json序列化转换器
public class PlanBasedPropertyConverter : JsonConverter<object>
{
    private readonly string _userPlan;
    private readonly Dictionary<string, List<string>> _fieldRules;

    public PlanBasedPropertyConverter(string userPlan, Dictionary<string, List<string>> fieldRules)
    {
        _userPlan = userPlan;
        _fieldRules = fieldRules;
    }

    public override bool CanConvert(Type typeToConvert) 
        => !typeToConvert.IsPrimitive && !typeToConvert.IsEnum && typeToConvert != typeof(string);

    public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        => throw new NotImplementedException("此转换器仅用于序列化输出");

    public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
    {
        if (!_fieldRules.TryGetValue(_userPlan, out var fieldsToRemove))
        {
            JsonSerializer.Serialize(writer, value, options);
            return;
        }

        writer.WriteStartObject();
        foreach (var property in value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            if (!fieldsToRemove.Contains(property.Name))
            {
                var propertyValue = property.GetValue(value);
                writer.WritePropertyName(property.Name);
                JsonSerializer.Serialize(writer, propertyValue, property.PropertyType, options);
            }
        }
        writer.WriteEndObject();
    }
}

2. 注册全局过滤器

在Program.cs中添加全局过滤器,让所有控制器生效:

builder.Services.AddControllers(options =>
{
    options.Filters.Add<FilterFieldsByPlanAttribute>();
});

方案二:自定义Json输出格式化器

如果需要更底层的序列化控制,可以替换默认的Json输出格式化器,所有Json响应都会经过该格式化器处理。

1. 实现自定义格式化器

using Microsoft.AspNetCore.Mvc.Formatters;
using System.Text.Json;

public class PlanBasedJsonOutputFormatter : SystemTextJsonOutputFormatter
{
    public PlanBasedJsonOutputFormatter(JsonSerializerOptions options) : base(options) { }

    public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
    {
        var user = context.HttpContext.User;
        var userPlan = user.FindFirstValue("UserPlan");
        if (string.IsNullOrEmpty(userPlan) || context.Object == null)
        {
            await base.WriteResponseBodyAsync(context, selectedEncoding);
            return;
        }

        var fieldRules = new Dictionary<string, List<string>>
        {
            { "Basic", new List<string> { "PremiumFeature", "AdvancedAnalytics" } },
            { "Pro", new List<string> { "EnterpriseSupport" } }
        };

        var modifiedOptions = new JsonSerializerOptions(SerializerOptions);
        modifiedOptions.Converters.Add(new PlanBasedPropertyConverter(userPlan, fieldRules));
        
        var json = JsonSerializer.Serialize(context.Object, modifiedOptions);
        await context.HttpContext.Response.WriteAsync(json, selectedEncoding);
    }
}

2. 替换默认格式化器

在Program.cs中替换默认的Json输出格式化器:

builder.Services.AddControllers(options =>
{
    // 移除默认的SystemTextJson格式化器
    var defaultFormatter = options.OutputFormatters.OfType<SystemTextJsonOutputFormatter>().FirstOrDefault();
    if (defaultFormatter != null)
    {
        options.OutputFormatters.Remove(defaultFormatter);
    }
    // 添加自定义格式化器
    options.OutputFormatters.Add(new PlanBasedJsonOutputFormatter(new JsonSerializerOptions(JsonSerializerDefaults.Web)));
});

方案三:模型内条件过滤(适合单个模型定制)

如果只需针对特定模型处理,可以在模型中添加过滤方法,再通过过滤器调用:

public class UserResponse
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string PremiumFeature { get; set; }
    public string EnterpriseSupport { get; set; }

    public void ApplyPlanFilter(string userPlan)
    {
        switch (userPlan)
        {
            case "Basic":
                PremiumFeature = null;
                EnterpriseSupport = null;
                break;
            case "Pro":
                EnterpriseSupport = null;
                break;
        }
    }
}

然后在过滤器中调用该方法即可,这种方式灵活性较低,适合局部场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 20:35:20