c# - 使用公开加密/解密值的单独类通过 Entity Framework 加密解密数据 : Linq statements fails

标签 c# linq entity-framework

除了我之前关于 Entity Framework 的问题。我的目的是在保存到 DB 之前加密字段并在从 DB 读取之前解密字段。我有从表 User 生成的类(User.cs)(具有 UserName 属性(要加密)并且我创建了一个单独的类 SecureUser with UserName如前所述加密/解密的属性。但我不确定如何将这个新的 SecureUser 类映射到 DB 而不是以前的 POCO 类用户。当我用 SecureUser 类中的 UserName 替换 UserName 时,我的 Linq 查询失败。我尝试做同样的事情部分类的事情,同样的事情发生。 任何建议将不胜感激!

[Table("Users")]
public class User
{

    #region database table column mapped fields
    [Key]
    [Required]
    public Int32 UserID { set; get; }

    [Required]
    [MaxLength(50)]
    public String UserName { set; get; }

    [Required]
    public Int32 CustID { set; get; }

//created the separate class as
public class SecureUser // UserViewModel
{
    // 
    private readonly User _user;

   public SecureUser(User user)
    {
        _user = user;
    }

    public string UserName
    {
        get { return Decrypt(_user.UserName); }
        set { _user.UserName = Encrypt(value); }
    }

最佳答案

我非常喜欢任何依赖于属性的解决方案。

假设您有一个实体类,其中包含一个或多个要加密存储在数据库中的属性。只需添加 [Encrypted] 属性即可。

[Encrypted] 
public string EncryptedProperty { get; set; }

现在创建一个自定义的 DbContext,它可以为您动态地进行加密/解密:

public class MyDB : IdentityDbContext<User>
{  
    //DBSet properties go here

    public MyDB()
    {
        ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += new ObjectMaterializedEventHandler(ObjectMaterialized);
    }

    #region Encryption

    public override int SaveChanges()
    {
        var contextAdapter = ((IObjectContextAdapter)this);

        contextAdapter.ObjectContext.DetectChanges(); //force this. Sometimes entity state needs a handle jiggle

        var pendingEntities = contextAdapter.ObjectContext.ObjectStateManager
            .GetObjectStateEntries(EntityState.Added | EntityState.Modified)
            .Where(en => !en.IsRelationship).ToList();

        foreach (var entry in pendingEntities) //Encrypt all pending changes
            EncryptEntity(entry.Entity);

        int result = base.SaveChanges();

        foreach (var entry in pendingEntities) //Decrypt updated entities for continued use
            DecryptEntity(entry.Entity);

        return result;
    }

    public override async Task<int> SaveChangesAsync(System.Threading.CancellationToken cancellationToken)
    {
        var contextAdapter = ((IObjectContextAdapter)this);

        contextAdapter.ObjectContext.DetectChanges(); //force this. Sometimes entity state needs a handle jiggle

        var pendingEntities = contextAdapter.ObjectContext.ObjectStateManager
            .GetObjectStateEntries(EntityState.Added | EntityState.Modified)
            .Where(en => !en.IsRelationship).ToList();

        foreach (var entry in pendingEntities) //Encrypt all pending changes
            EncryptEntity(entry.Entity);

        var result = await base.SaveChangesAsync(cancellationToken);

        foreach (var entry in pendingEntities) //Decrypt updated entities for continued use
            DecryptEntity(entry.Entity);

        return result;
    }

    void ObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
    {
        DecryptEntity(e.Entity);
    }

    private void EncryptEntity(object entity)
    {
        //Get all the properties that are encryptable and encrypt them
        var encryptedProperties = entity.GetType().GetProperties()
            .Where(p => p.GetCustomAttributes(typeof(Encrypted), true).Any(a => p.PropertyType == typeof(String)));
        foreach (var property in encryptedProperties)
        {
            string value = property.GetValue(entity) as string;
            if (!String.IsNullOrEmpty(value))
            {
                string encryptedValue = EncryptionService.Encrypt(value);
                property.SetValue(entity, encryptedValue);
            }
        }
    }

    private void DecryptEntity(object entity)
    {
        //Get all the properties that are encryptable and decyrpt them
        var encryptedProperties = entity.GetType().GetProperties()
            .Where(p => p.GetCustomAttributes(typeof(Encrypted), true).Any(a => p.PropertyType == typeof(String)));

        foreach (var property in encryptedProperties)
        {
            string encryptedValue = property.GetValue(entity) as string;
            if (!String.IsNullOrEmpty(encryptedValue))
            {
                string value = EncryptionService.Decrypt(encryptedValue);
                this.Entry(entity).Property(property.Name).OriginalValue = value;
                this.Entry(entity).Property(property.Name).IsModified = false;
            }
        }
    }

    #endregion Encryption
}

然后添加一个类

class Encrypted : Attribute
{

}

来源:https://gist.github.com/albertbori/e95860644e69c1572441

关于c# - 使用公开加密/解密值的单独类通过 Entity Framework 加密解密数据 : Linq statements fails,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27712088/

相关文章:

c# - 在不创建该对象的新实例的情况下编辑 list<objects> 中的对象?

c# - 即使没有空值,为什么会发出有关可为空类型的警告?

c# - EF6 Model First 无法导入函数

c# - Dispatcher.BeginInvoke 始终返回 DispatcherOperationStatus.Pending 状态

c# - 我刚刚使用通用存储库在 Entity Framework 之上实现了工作单位模式。我实际上完成了什么?

c# - FFMPEG 将音轨连接到更长的视频轨道时,音频循环

c# - 转换 List<T> 中的 IEnumerable

c# - 如何使用 C# 在 .Net 中的类型对象列表中选择对象属性的所有值

c# - 为什么在 Entity Framework 中使用数据结构更好

c# - Entity Framework 更改 Id 类型