1

当存储在数据库中时,我需要加密一组特定字段的值。我正在使用 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,我确信可能有更好的方法来处理拦截并检测它是 getter 还是 setter 等。如下:

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 ();
        }
    }
}
4

1 回答 1

2

也许我太简单了,但是仅仅向SecretEntity允许加密和解密的部分添加一个新属性就足够了吗?您可以将 LINQ to SQL 生成的原始属性设为内部:

public partial class SecretEntity
{
    public string BigSecret
    {
        get { return Decrypt(this.BigSecretInternal); }
        set { this.BigSecretInternal = Encrypt(value); }
    }
}
于 2010-11-01T07:22:23.947 回答