我需要在存储在数据库中时加密特定字段集的值。 我正在使用LINQ-to-SQL。
我的方法:在将实体写入数据库之前,对实体中匹配属性的值进行透明加密。
我已经使用Castle Dynamic Proxy编写了一个拦截器,它将加密setter上的相关属性并在getter上解密它。以下是我如何使用它:
var secretEntity = <Get a SecretEntity from the DataContext>;
ProxyGenerator pg = new ProxyGenerator();
// (Typing from memory here, so excuse possible method errors, but you get the gist)
// Reassign to now reference the dynamic proxy.
secretEntity = pg.CreateProxyWithTarget (secretEntity , new EncryptionInterceptor());
secretEntity.BigSecret = "Silentium"; // Does the encryption via the interceptor.
var decryptedSecret = secretEntity.BigSecret; // Does the decryption via the interceptor.
现在这一切都很好用,但我不想手动将每个SecretEntity实例包装在动态代理中。 所以我正在寻找一种自动化方法,这样当我得到一个SecretEntity实例时,它已经包含在代理中。
有没有办法通过某种方式挂钩到LINQ-to-SQL DataContext,以便它返回代理?
我正在使用MVC,因此我使用视图模型来显示我的数据,并使用AutoMapper在实体和视图模型之间来回映射。所以我在想,如果LINQ-to-SQL DataContext方法不起作用,也许可以挂钩映射例程并在映射到视图模型之前将实体包装在代理中。 因此,我很高兴在使用AutoMapper时找到一个名为BeforeMap的方法。 所以我试过
.BeforeMap ((se, sevm) => se = pg.CreateProxyWithTarget (se, new EncryptionInterceptor()));
// (Again, typing from memory).
但没有运气。我认为这是因为一旦BeforeMap方法运行完毕,重新分配代理的“se”引用就没有效果。
创建新的SecretEntity时,我可以使用Ninject自动执行代理包装过程,但是Ninject不会对我从DataContext返回的现有实体起作用。
我使用Castle Dynamic Proxy只需要几个小时,而AutoMapper对我的了解并不多。所以我希望有人可以给我一个快速指针去看看。
谢谢。
修改
为了完整起见,我想我会为那些可能感兴趣的人添加拦截器的实现。我不太了解Castle Dynamic Proxy,我确信可能有更好的方法来处理拦截并检测它是吸气剂还是定位器等。 以下是:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.DynamicProxy;
using TunedIn.Base.Model;
using TunedIn.Base.Ninject;
using TunedIn.Base.Extensions.StringExtensions;
namespace TunedIn.Base.Encryption
{
public class PropertyEncryptionInterceptor : IInterceptor
{
public void Intercept (IInvocation invocation)
{
IPersonEncryptedFields p = invocation.InvocationTarget as IPersonEncryptedFields;
if (p == null)
throw new ApplicationException ("{0} expects the InvocationTarget of the dynamic proxy binding to implement {1}, but {2} does not.".FormatI (typeof (PropertyEncryptionInterceptor).FullName, typeof (IPersonEncryptedFields).FullName, invocation.InvocationTarget.GetType ().FullName));
if (invocation.Method.Name.StartsWith ("set_"))
{
string val = (string)invocation.GetArgumentValue (0);
val = Kernel.Get<IStringCrypto> ().Encrypt (val);
invocation.SetArgumentValue (0, val);
invocation.Proceed ();
}
else if (invocation.Method.Name.StartsWith ("get_"))
{
invocation.Proceed ();
string ret = invocation.ReturnValue.ToString ();
ret = Kernel.Get<IStringCrypto> ().Decrypt (ret);
invocation.ReturnValue = ret;
}
else
invocation.Proceed ();
}
}
}
答案 0 :(得分:2)
也许我太简单了,但仅仅为允许加密和解密的部分SecretEntity
添加新属性是不够的?您可以创建由LINQ to SQL internal生成的原始属性:
public partial class SecretEntity
{
public string BigSecret
{
get { return Decrypt(this.BigSecretInternal); }
set { this.BigSecretInternal = Encrypt(value); }
}
}