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

基于JsonApiDotNetCore用数据库UDF实现加密字段过滤的可行性问询

实现基于数据库加密函数的JSON API过滤

这种需求完全可行,核心是结合EF Core用户定义函数映射和JsonApiDotNetCore自定义过滤表达式解析,以下是具体实现步骤:

1. 在EF Core中映射数据库加密函数

首先需要让EF Core识别并能翻译你的dbo.DecryptData函数,步骤如下:

1.1 定义静态扩展方法

创建一个静态类,声明与数据库函数签名匹配的方法,用DbFunction特性标记:

public static class DbFunctionExtensions
{
    [DbFunction("DecryptData", Schema = "dbo")]
    public static string DecryptData(byte[] encryptedData)
    {
        // 仅用于EF Core查询翻译,无需实现具体逻辑
        throw new NotImplementedException("此方法仅为EF Core查询转换使用");
    }
}

1.2 在DbContext中注册函数

在你的DbContext的OnModelCreating方法中配置函数映射:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    var decryptMethod = typeof(DbFunctionExtensions).GetMethod(nameof(DbFunctionExtensions.DecryptData));
    modelBuilder.HasDbFunction(decryptMethod)
                .HasTranslation(args =>
                    new SqlFunctionExpression(
                        "dbo.DecryptData",
                        args,
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        typeof(string),
                        null));
}

2. 扩展JsonApiDotNetCore的过滤表达式解析器

JsonApiDotNetCore默认不识别自定义函数,需要重写过滤表达式构建器,解析DecryptData函数调用并转换为EF可识别的表达式:

2.1 创建自定义FilterExpressionBuilder

public class CustomFilterExpressionBuilder : DefaultFilterExpressionBuilder
{
    public CustomFilterExpressionBuilder(ResourceGraph resourceGraph, IResourceFactory resourceFactory, IFieldParser fieldParser)
        : base(resourceGraph, resourceFactory, fieldParser)
    {
    }

    protected override Expression VisitFunctionCall(FunctionCallExpression functionCall, QueryExpressionContext context)
    {
        // 识别DecryptData函数调用
        if (functionCall.Name.Equals("DecryptData", StringComparison.OrdinalIgnoreCase))
        {
            // 解析函数参数(必须是实体字段)
            var fieldExpr = Visit(functionCall.Arguments[0], context) as MemberExpression;
            if (fieldExpr == null)
            {
                throw new JsonApiException(new Error(HttpStatusCode.BadRequest, "DecryptData仅支持实体字段作为参数"));
            }

            // 调用已注册的EF函数方法
            var decryptMethod = typeof(DbFunctionExtensions).GetMethod(nameof(DbFunctionExtensions.DecryptData));
            return Expression.Call(decryptMethod, fieldExpr);
        }

        // 其他函数调用使用默认解析逻辑
        return base.VisitFunctionCall(functionCall, context);
    }
}

2.2 替换默认服务

在DI容器中注册自定义的过滤表达式构建器,替换默认实现:

services.AddJsonApi<AppDbContext>(options =>
{
    // 你的其他JsonApi配置
})
.AddScoped<IFilterExpressionBuilder, CustomFilterExpressionBuilder>();

3. 测试过滤请求

现在发送你期望的JSON API过滤请求:

/api/v1/customer?filter=equals(DecryptData(firstName), 'Theodore')

EF Core会生成对应的SQL语句:

WHERE dbo.DecryptData([c].[FirstName]) = N'Theodore'

注意事项

  • 确保Customer实体的FirstName属性类型为byte[],且EF映射到数据库的varbinary列
  • 数据库中的DecryptData函数必须接收varbinary参数并返回nvarchar类型
  • 若需要支持多个加密字段,此方案无需额外修改,直接在过滤语句中使用DecryptData(字段名)即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:38:20