在这个答案中,我将列出处理 EF 中的加密列需要做的事情。因此,有问题的列将具有VARBINARY(MAX) 的类型。假设您的表看起来像这样:
CREATE TABLE dbo.Person
(
SomeId int NOT NULL,
CreatedByUserId uniqueidentifier NULL,
CreatedUtcDate datetimeoffset(7) NULL,
Rowversion timestamp NULL,
FirstName varbinary(MAX) NULL,
LastName varbinary(MAX) NULL
)
第 1 步 - 创建一个返回解密列的视图。该视图应该与您的表基本相同,但是对于包含加密数据的列,它应该返回解密的数据。它看起来像这样:
CREATE VIEW [dbo].[v_Person]
AS
SELECT [SomeId]
,[CreatedByUserId]
,[CreatedUtcDate]
,[RowVersion]
,CONVERT(NVARCHAR(50),DECRYPTBYKEY([FirstName])) [FirstName]
,CONVERT(NVARCHAR(50),DECRYPTBYKEY([LastName])) [LastName]
FROM [dbo].[Person]
第 2 步 - 创建域模型 Person 类,使用 string 作为相关属性类型,而不是 byte[](请注意上面 View 中的 select 语句,我们在其中进行了转换解密后的列到NVARCHAR)。
public class Person
{
public int SomeId { get; set; }
public string FirstName { get; set; } // string, not binary
public string LastName { get; set; } // string, not binary
public Guid CreatedByUserId { get; set; }
public DateTime CreatedUtcDate { get; set; }
public int SomeForeignKeyId { get; set; }
}
第 3 步 - 我们需要为该域类设置映射。 (我在这里提出的解决方案是针对 EF6。我知道 EF Core 还不支持单独的映射文件,因此这需要在 DbContext 的 OnModelCreating 事件中完成)。为您的域对象创建一个映射类,如下所示:
public class PersonMap : EntityTypeConfiguration<Person>
{
public PersonConfiguration(string schema)
{
ToTable("v_Person", schema); // note we map to the View
HasKey(x => x.SomeId);
// ... other properties elided for brevity
Property(x => x.FirstName)
.HasColumnName(@"FirstName")
.HasColumnType("nvarchar")
.IsOptional()
.HasMaxLength(50);
Property(x => x.LastName)
.HasColumnName(@"LastName")
.HasColumnType("nvarchar")
.IsOptional()
.HasMaxLength(50);
// Foreign keys
HasRequired(a => a.LogbookEntry)
.WithOptional(b => b.Person)
.WillCascadeOnDelete(false);
MapToStoredProcedures(p =>
p.Insert(i => i.HasName("Insert_Person"))
.Update(u => u.HasName("Update_Person"))
.Delete(d => d.HasName("Delete_Person")));
}
}
请注意我们如何映射到视图 v_Person,而不是原始表。
还要注意对MapToStoredProcedures 的调用,我接下来会解释。
第 4 步 - 最后一步是为插入、更新和删除创建一些存储过程。当您调用 SaveChanges 时,这些将由 EF 调用,并且将根据实体拥有的 EntityState 调用相关的存储过程。我不会列出所有 3 个,但 Update 存储过程的示例可能类似于:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Update_Person]
@SomeId INT,
@CreatedByUserId UNIQUEIDENTIFIER,
@CreatedUtcDate DATETIME,
@RowVersion_Original timestamp,
@FirstName NVARCHAR(50),
@LastName NVARCHAR(50) = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE @CertKey NVARCHAR(7) = 'CertKey';
UPDATE PersonDetail
SET
FirstName = ENCRYPTBYKEY(KEY_GUID(@CertKey), @FirstName),
LastName = ENCRYPTBYKEY(KEY_GUID(@CertKey), @LastName)
WHERE SomeId = @SomeId
SELECT SomeId, RowVersion
FROM PersonDetail
WHERE SomeId = @SomeId
END
如果您做得更好,请随时发表评论。
干杯