基于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
相关产品推荐
相关产品推荐

