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

.NET中如何在API调用前执行解密逻辑且不修改方法签名?

当然可以实现!你完全不用折腾修改API方法的签名,.NET早就给我们准备了优雅的解决方案,能在JSON反序列化之前就完成解密操作。下面给你分享两种最实用的实现方式:

方案一:自定义输入格式化器(Custom Input Formatter)

这是最贴合你需求的方式,因为ASP.NET Core的输入格式化器本身就负责将请求体转换为模型对象。我们只需要扩展它的逻辑,先完成解密再执行反序列化。

实现自定义格式化器

public class EncryptedJsonInputFormatter : TextInputFormatter
{
    private readonly JsonSerializerOptions _jsonOptions;

    public EncryptedJsonInputFormatter(JsonSerializerOptions jsonOptions)
    {
        _jsonOptions = jsonOptions;
        // 指定我们处理的Content-Type,比如自定义的加密JSON类型
        SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/encrypted-json"));
        SupportedEncodings.Add(Encoding.UTF8);
        SupportedEncodings.Add(Encoding.Unicode);
    }

    public override bool CanRead(InputFormatterContext context)
    {
        // 可以根据请求头或其他条件判断是否需要触发解密逻辑
        return base.CanRead(context);
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
    {
        var httpContext = context.HttpContext;
        using var reader = new StreamReader(httpContext.Request.Body);
        // 读取加密的请求体字符串
        var encryptedContent = await reader.ReadToEndAsync();
        
        // 替换成你实际的解密逻辑(比如AES、RSA等)
        var decryptedContent = Decrypt(encryptedContent);
        
        // 将解密后的字符串反序列化为目标模型(比如TodoItem)
        var model = JsonSerializer.Deserialize(decryptedContent, context.ModelType, _jsonOptions);
        
        return await InputFormatterResult.SuccessAsync(model);
    }

    // 示例解密方法,请替换为你的真实加密算法实现
    private string Decrypt(string encryptedText)
    {
        // 这里只是示例,实际请使用你的解密逻辑
        var bytes = Convert.FromBase64String(encryptedText);
        return Encoding.UTF8.GetString(bytes);
    }
}

注册格式化器

在Program.cs中把自定义格式化器添加到框架的输入格式化器集合中:

builder.Services.AddControllers(options =>
{
    // 获取默认的JSON序列化配置
    var jsonOptions = options.JsonSerializerOptions;
    // 将自定义格式化器放在默认JSON格式化器前面,确保优先触发
    options.InputFormatters.Insert(0, new EncryptedJsonInputFormatter(jsonOptions));
});

使用方式

发送请求时,将Content-Type设置为application/encrypted-json,框架就会自动调用我们的格式化器完成解密+反序列化,你的原PutTodoItem方法完全不需要修改。

方案二:使用Action Filter(动作过滤器)

这种方式适合需要全局或批量处理多个接口的场景,在请求进入API方法前拦截请求体,解密后再让默认的序列化流程处理。

实现解密过滤器

public class DecryptRequestBodyFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        var request = context.HttpContext.Request;
        // 启用请求体缓冲(默认请求体只能读取一次)
        request.EnableBuffering();
        
        using var reader = new StreamReader(request.Body, Encoding.UTF8, leaveOpen: true);
        var encryptedContent = reader.ReadToEnd();
        
        // 执行解密逻辑
        var decryptedContent = Decrypt(encryptedContent);
        
        // 将解密后的内容重新写入请求体,并重置位置到开头
        request.Body.Position = 0;
        using var writer = new StreamWriter(request.Body, Encoding.UTF8, leaveOpen: true);
        writer.Write(decryptedContent);
        writer.Flush();
        request.Body.Position = 0;
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // 可在此处做后续清理或日志记录
    }

    // 示例解密方法,请替换为你的真实实现
    private string Decrypt(string encryptedText)
    {
        var bytes = Convert.FromBase64String(encryptedText);
        return Encoding.UTF8.GetString(bytes);
    }
}

注册过滤器

可以选择全局注册(对所有API生效)或局部注册(仅对特定控制器/方法生效):

// 全局注册(Program.cs)
builder.Services.AddControllers(options =>
{
    options.Filters.Add<DecryptRequestBodyFilter>();
});

// 局部注册(控制器或方法上)
// [ServiceFilter(typeof(DecryptRequestBodyFilter))]
// public class TodoItemsController : ControllerBase
// {
//     // ...
// }
方案对比
  • 自定义输入格式化器:更规范,适合处理特定Content-Type的加密请求,逻辑边界清晰。
  • Action Filter:更灵活,适合全局批量处理解密需求,无需修改请求的Content-Type。

两种方案都能让你保持原有的PutTodoItem方法签名不变,所有解密逻辑都在框架层面处理,代码更整洁易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:29:12