DB に格納するときに、特定のフィールド セットの値を暗号化する必要があります。LINQ-to-SQL を使用しています。
私のアプローチ: DB に書き込まれる前に、エンティティ内の一致するプロパティの値を透過的に暗号化します。
関連するプロパティをセッターで暗号化し、ゲッターで復号化するキャッスル ダイナミック プロキシを使用したインターセプターを既に作成しました。これが私がそれを使用する方法です:
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 ();
}
}
}