dotnetcore / dotnetcore/FreeSql

多个FreeSQL实例之间的AOP事件会互相影响,导致实体对象的数据和状态异常

Open
#2,159 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
4.4k
Forks
910
PR merge metrics
No merged PRs in 30d

Description

#### 问题描述及重现代码:
##### 背景:
对于身份证号和手机号等敏感信息,要求在数据库中加密存储。

###### EFCore:之前使用的EFCore,里面有一个值转换器的东西可以自动实现插入时加密,查询时解密。非常好用,业务只关心原始值,而不用关心加密值。
###### FreeSQL:没有找到类似的值转换器功能,只能通过AOP事件来实现类似功能。
###### bug描述:多个 FreeSql 实例时,AOP事件会互相影响,导致状态不一致。
###### bug重现步骤(以自动加解密的场景为例):
###### 第一步:定义两个 FreeSql 实例 fsql1 和 fsql2,fsql1 配置AOP的自动值处理(插入加密)或DataReader拦截(查询解密),fsql2 不配置。
###### 第二步:使用 fsql1 插入一条数据,触发AOP自动加密。
###### 第三步:使用 fsql1(触发自动解密) 和 fsql2 分别查询该数据。
###### 第四步:期望 fsql1 查询结果为解密后的原始值,fsql2 查询结果为加密后的存储值。但实际结果是两个实例查询结果均为解密后的原始值。
``` C#

public class FreesqlAutoCryptoTest2
{
public record Fsql1;
public record Fsql2;

///
/// 背景:对于身份证号和手机号等敏感信息,要求在数据库中加密存储。
/// EFCore:之前使用的EFCore,里面有一个值转换器的东西可以自动实现插入时加密,查询时解密。非常好用,业务只关心原始值,而不用关心加密值。
/// FreeSQL:没有找到类似的值转换器功能,只能通过AOP事件来实现类似功能。
/// bug描述:多个 FreeSql 实例时,AOP事件会互相影响,导致状态不一致。
/// bug重现步骤(以自动加解密的场景为例):
/// 第一步:定义两个 FreeSql 实例 fsql1 和 fsql2,fsql1 配置AOP的自动值处理(插入加密)或DataReader拦截(查询解密),fsql2 不配置。
/// 第二步:使用 fsql1 插入一条数据,触发AOP自动加密。
/// 第三步:使用 fsql1(触发自动解密) 和 fsql2 分别查询该数据。
/// 第四步:期望 fsql1 查询结果为解密后的原始值,fsql2 查询结果为加密后的存储值。但实际结果是两个实例查询结果均为解密后的原始值。
///
[Test]
public void InsertUpdateAutoEnrcyptTests()
{
var fsql1 = ProvideFsql();

// 在第一个 FreeSql 实例上配置自动加解密
AopConfig(fsql1);

// 第二个 FreeSql 实例不配置自动加解密
var fsql2 = ProvideFsql();

var stu0 = new Student
{
StuName = "测试ceshics张三A测试ceshi",
CertificateType = "1",
CertificateNo = "516423156476894261",
MobilePhone = "12546987465",
MobilePhone2 = "12546987789",
Password = "123456789456",
StudentStatus = 1,
RegisterTime = DateTime.Now
};
// 第一个实例插入数据,自动加密后存到数据库。
// bug1:这里自动加密会修改原始对象stu0的值。按逻辑说,这里应该修改,但是这种场景应用较少。
// 能不能提供一个选项或方法,不修改原始对象?
var stuId = fsql1.Insert(stu0).ExecuteIdentity();

// 第一个实例查询,触发自动解密,查询结果是解密后的值
var stu1 = fsql1.Select().Where(s => s.StuName.Equals(stu0.StuName)).ToOne();

// 第二个实例查询,不触发自动解密,查询结果是加密后的值
var stu2 = fsql2.Select().Where(s => s.StuName.Equals(stu0.StuName)).ToOne();
fsql1.Delete().Where(s => s.StuName.Equals(stu0.StuName)).ExecuteAffrows();

using (Assert.EnterMultipleScope())
{
Assert.That(stu1, Is.Not.EqualTo(stu2));

// 验证第一个实例查询结果是解密后的值
Assert.That(stu1.CertificateNo, Is.EqualTo("516423156476894261"));
Assert.That(stu1.MobilePhone, Is.EqualTo("12546987465"));
Assert.That(stu1.MobilePhone2, Is.EqualTo("12546987789"));

// 验证第二个实例查询结果是加密后的值
Assert.That(stu2.CertificateNo, Is.EqualTo("D3DF4F22F89BC68C485BD7056A9DABB1D07E061A156FCCB7C4CA10FCD054F2335A5B53"));
Assert.That(stu2.MobilePhone, Is.EqualTo("83CD25466A9085D9A2BE0C34456E58DC5F8B7B"));
Assert.That(stu2.MobilePhone2, Is.EqualTo("19BC0F7AC7258992C25005E67E6C7A36BF07E2"));
}
}
private static IFreeSql ProvideFsql()
{
var config = new ConfigurationBuilder().AddEnvironmentVariables().Build();
var dbConn = ConnectionStringHelper.BuildDbPlaceholder(config.GetConnectionString("ZhongkaoDbPgsql"), "guang_an");
var fsql = new FreeSqlBuilder()
.UseConnectionString(DataType.PostgreSQL, dbConn)
.UseNameConvert(NameConvertType.PascalCaseToUnderscoreWithLower)
.Build();

return fsql;
}
private static IFreeSql AopConfig(IFreeSql fsql)
{

fsql.Aop.AuditValue += (s, e) =>
{
if (typeof(Student) == e.Property.DeclaringType)
{
switch (e.Property.Name)
{
case nameof(Student.CertificateNo):
case nameof(Student.MobilePhone):
case nameof(Student.MobilePhone2):
e.Value = DataEncryptConverterUtility.Forward(e.Value as string)!;
break;
}
}
};

fsql.Aop.AuditDataReader += (s, e) =>
{
Console.WriteLine($"FreeSql自动解密触发,字段: {e.Property.Name}");
switch (e.Property.Name)
{
case nameof(Student.CertificateNo):
case nameof(Student.MobilePhone):
case nameof(Student.MobilePhone2):
try
{
e.Value = DataEncryptConverterUtility.Backward(e.Value as string)!;
}
catch (Exception ex)
{
Console.WriteLine($"FreeSql自动解密失败,字段: {e.Property.Name}, 错误: {ex.Message}");
throw;
}
break;
}
};
return fsql;
}

}

```
### 执行结果

Image


### 数据库版本
(openGauss 3.0.3 build 46134f73) compiled at 2023-01-10 22:43:35 commit 0 last mr on x86_64-unknown-linux-gnu, compiled by g++ (GCC) 7.3.0, 64-bit

### 安装的Nuget包
FreeSql.Provider.PostgreSQL" Version="3.5.212"

### .net framework/. net core? 及具体版本
net10.0

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.