在EF Core中为数据表按列加密存储
假设有User表
public class User : Entity<int>
{
public int Id { get; set; }
public string UserName { get; set; }
public string Name { get; set; }
public string IdentificationNumber { get; set; }
}
其中有身份证号码IdentificationNumber列,需要加密存储,该如何实现?

创建一个值转换器,继承ValueConverter<TModel, string>类型。其中泛型TModel为实体中属性的类型。
转换器将实体中属性类型,通过AES加密算法,转换为Base64编码字符串类型,存储到数据库中。当从数据库中读取数据时,再通过AES解密算法,将Base64编码字符串类型转换为实体中属性类型。
若实体类型为byte[],则不需要转换为Base64编码字符串类型,直接对二进制数据进行加密和解密。此转换器可以用于加密存储图片、文件等二进制数据。
AES加密算法是一种对称加密算法,加密和解密使用相同的密钥。在加密和解密时,需要指定密钥、初始向量、盐值等参数。在转换器中,将这些参数设置为静态属性,方便在使用时,进行修改。
代码如下:
public class EncryptionConverter<TModel> : ValueConverter<TModel, string>
{
public const int DefaultKeysize = 256;
public static string DefaultPassPhrase { get; set; }
public static byte[] DefaultInitVectorBytes { get; set; }
public static byte[] DefaultSalt { get; set; }
public EncryptionConverter()
: base(
x => Encrypt(x),
x => Decrypt(x))
{
DefaultPassPhrase = "gsKnGZ041HLL4IM8";
DefaultInitVectorBytes = Encoding.ASCII.GetBytes("jkE49230Tf093b42");
DefaultSalt = Encoding.ASCII.GetBytes("hgt!16kl");
}
private static string Encrypt(TModel input)
{
try
{
byte[] inputData = input switch
{
string => Encoding.UTF8.GetBytes(input.ToString()),
byte[] => input as byte[],
_ => null,
};
using (var password = new Rfc2898DeriveBytes(DefaultPassPhrase, DefaultSalt))
{
var keyBytes = password.GetBytes(DefaultKeysize / 8);
using (var symmetricKey = Aes.Create())
{
symmetricKey.Mode = CipherMode.CBC;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, DefaultInitVectorBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(inputData, 0, inputData.Length);
cryptoStream.FlushFinalBlock();
var cipherTextBytes = memoryStream.ToArray();
var rawString = Convert.ToBase64String(cipherTextBytes);
return rawString;
}
}
}
}
}
}
catch (Exception ex)
{
LogHelper.LogException(ex);
return input.ToString();
}
}
private static TModel Decrypt(string input)
{
try
{
var cipherTextBytes = Convert.FromBase64String(input);
using (var password = new Rfc2898DeriveBytes(DefaultPassPhrase, DefaultSalt))
{
var keyBytes = password.GetBytes(DefaultKeysize / 8);
using (var symmetricKey = Aes.Create())
{
symmetricKey.Mode = CipherMode.CBC;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, DefaultInitVectorBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
int totalDecryptedByteCount = 0;
while (totalDecryptedByteCount < plainTextBytes.Length)
{
var decryptedByteCount = cryptoStream.Read(
plainTextBytes,
totalDecryptedByteCount,
plainTextBytes.Length - totalDecryptedByteCount
);
if (decryptedByteCount == 0)
{
break;
}
totalDecryptedByteCount += decryptedByteCount;
}
byte[] outputData = null;
if (typeof(TModel) == typeof(string))
{
outputData = Encoding.UTF8.GetBytes(plainTextBytes.ToString());
}
else if (typeof(TModel) == typeof(byte[]))
{
outputData = plainTextBytes as byte[];
};
var rawString = Encoding.UTF8.GetString(outputData, 0, totalDecryptedByteCount);
return (TModel)Convert.ChangeType(rawString, typeof(TModel));
}
}
}
}
}
}
catch (Exception ex)
{
// 记录异常
// LogHelper.LogException(ex);
return (TModel)Convert.ChangeType(input, typeof(TModel));
}
}
}
在DbContext中,重写OnModelCreating方法,为User表的IdentificationNumber列,添加值转换器。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().Property(c => c.IdentificationNumber).HasConversion<EncryptionConverter<string>>();
}
再次调用Add方法插入数据时,可以看到IdentificationNumber列已被加密了

在EF Core中为数据表按列加密存储的更多相关文章
- 9.翻译系列:EF 6以及EF Core中的数据注解特性(EF 6 Code-First系列)
原文地址:http://www.entityframeworktutorial.net/code-first/dataannotation-in-code-first.aspx EF 6 Code-F ...
- 文章翻译:ABP如何在EF core中添加数据过滤器
原文地址:https://aspnetboilerplate.com/Pages/Documents/Articles%5CHow-To%5Cadd-custom-data-filter-ef-cor ...
- EF Core中如何正确地设置两张表之间的关联关系
数据库 假设现在我们在SQL Server数据库中有下面两张表: Person表,代表的是一个人: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ...
- 20.1翻译系列:EF 6中自动数据迁移技术【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/automated-migration-in-code-first.aspx EF 6 ...
- 9.4 翻译系列:EF 6以及 EF Core中的NotMapped特性(EF 6 Code-First系列)
原文链接:http://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-f ...
- EF Core中如何通过实体集合属性删除从表的数据
假设在数据库中有两个表:Person表和Book表,Person和Book是一对多关系 Person表数据: Book表数据: 可以看到数据库Book表中所有的数据都属于Person表中"F ...
- EF Core 中多次从数据库查询实体数据,DbContext跟踪实体的情况
使用EF Core时,如果多次从数据库中查询一个表的同一行数据,DbContext中跟踪(track)的实体到底有几个呢?我们下面就分情况讨论下. 数据库 首先我们的数据库中有一个Person表,其建 ...
- EF Core中如何设置数据库表自己与自己的多对多关系
本文的代码基于.NET Core 3.0和EF Core 3.0 有时候在数据库设计中,一个表自己会和自己是多对多关系. 在SQL Server数据库中,现在我们有Person表,代表一个人,建表语句 ...
- EF Core中避免贫血模型的三种行之有效的方法(翻译)
Paul Hiles: 3 ways to avoid an anemic domain model in EF Core 1.引言 在使用ORM中(比如Entity Framework)贫血领域模型 ...
- EF Core中执行Sql语句查询操作之FromSql,ExecuteSqlCommand,SqlQuery
一.目前EF Core的版本为V2.1 相比较EF Core v1.0 目前已经增加了不少功能. EF Core除了常用的增删改模型操作,Sql语句在不少项目中是不能避免的. 在EF Core中上下文 ...
随机推荐
- Vue-数据代理
Vue中的数据代理 数据代理定义 所谓数据代理,就是通过一个对象代理对另一个对象中的属性的操作(读/写).说白了就是操作一个对象上的属性可以读取和修改另一个对象上的属性,这种关系就叫做数据代理. 在V ...
- SQL教程
SQL教程 SQL简介 SQL (Structured Query Language:结构化查询语言) 是用于管理关系数据库管理系统(RDBMS). SQL 的范围包括数据插入.查询.更新和删除,数据 ...
- Vivado中综合,实现,编程和调试工程可能会出现的问题及解决方案
Xilinx公司的IDE(集成开发环境) Vivado用处广泛,学会使用Vivado对FPGA的学习至关重要,这里以PRX100-D开发板为例,对Vivado的学习使用进行探讨.本文将会持续更新,列出 ...
- flutter 环境配置以及我的第一个flutter程序(Hello World)
电脑配置: 操作系统: Windows 7 或更高版本 (64-bit) 磁盘空间: 400 MB (不包括Android Studio的磁盘空间). Windows下所需安装有: 1.Flutter ...
- web后端之连接mysql
1建立java enterprise项目 2在WEB-INF目录下建立lib目录把jdbc用的mysql-connector-java.jar包复制过来 3添加依赖 4编写class 或在 ...
- LeetCode 之 111. 二叉树的最小深度
原题链接 思路: 递归计算每个子树的深度,返回左右子树中深度小的值: 由于题目中要求的是到最近叶子节点的深度,所以需要判断 左右子树为空的情况: python/python3: class Solut ...
- 渲染器的实现(1)--《vue.js设计与实现》
function renderer(domString, container) { container.innerHTML = domString } let count = ref(1) rende ...
- C++ read 读取字节数与设置不一样
当需要读取二进制文件时,C++可以采用ofstream流,并设置模式为ios::binary,就可以通过read函数进行按照字节读取了. 需要注意的是: 如果模式未进行设置,默认将以文本方式读取,此时 ...
- 动力节点的MySQL的34题目的第7题的我的参考答案
以下是:薪水的平均等级最低的部门的名称 select t4.t4deptno,t4.t4grade,d1.dname from( ##求出各部门平均等级begin select avg(t3.t3gr ...
- pandas加速读取数据记录csv大文件处理
def readf(file): t0 = time.time() data=pd.read_csv(file,low_memory=False,encoding='gbk' #,nrows=100 ...