2010-11-01 37 views
1

J'ai besoin de chiffrer la valeur d'un ensemble spécifique de champs lorsqu'ils sont stockés dans la base de données. J'utilise LINQ-to-SQL.Nécessité d'intercepter toutes les entités LINQ-to-SQL avec Castle Dynamic Proxy, peut-être avec AutoMapper

Mon approche: Chiffrer de manière transparente la valeur des propriétés correspondantes dans l'entité avant qu'elle ne soit écrite dans la base de données.

J'ai déjà écrit un intercepteur avec Castle Dynamic Proxy qui cryptera la propriété concernée sur le setter et la décryptera sur le getter. Voici comment je l'utilise:

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. 

Maintenant tout cela fonctionne très bien, mais je ne veux pas avoir à envelopper manuellement chaque instance SecretEntity dans un proxy dynamique. Je suis donc à la recherche d'un moyen d'automatiser cela, de sorte que lorsque je reçois une instance de SecretEntity, elle est déjà enveloppée dans le proxy.

Existe-t-il un moyen de faire cela en se connectant d'une manière ou d'une autre dans le DataContext LINQ-to-SQL, de sorte qu'il rende les proxys? J'utilise MVC, donc j'utilise des modèles de vue pour afficher mes données et j'utilise AutoMapper pour mapper entre les entités et les modèles de vue. Donc, je pensais, si l'approche LINQ-to-SQL DataContext ne fonctionne pas, peut-être qu'il serait possible de se connecter à la routine de mappage et d'envelopper les entités dans les proxies avant qu'ils ne soient mappés aux modèles de vue. J'étais donc très excité de trouver une méthode appelée BeforeMap lors de l'utilisation d'AutoMapper. donc j'ai essayé

.BeforeMap ((se, sevm) => se = pg.CreateProxyWithTarget (se, new EncryptionInterceptor())); 
// (Again, typing from memory). 

Mais pas de chance. Je suppose que c'est parce que la réaffectation de la référence "se" au proxy n'a aucun effet une fois que la méthode BeforeMap est terminée.

Lors de la création d'un nouveau SecretEntity, je pouvais automatiser le processus d'enrobage de proxy en utilisant Ninject, mais Ninject ne fonctionnerait pas sur les entités existantes que je récupère du DataContext.

Ma promenade avec Castle Dynamic Proxy ne dure que quelques heures, et AutoMapper ne me connaît pas beaucoup mieux. Donc j'espère que quelqu'un pourra me donner un petit point de vue rapide.

Merci.

Modifier

Pour être complet, je pensais que je rajouterais la mise en œuvre de mon intercepteur pour ceux qui pourraient être intéressés. Ne sachant pas Castle Dynamic Proxy qui fonctionnent bien, je suis sûr qu'il pourrait y avoir une meilleure façon de gérer l'interception et la détection que ce soit un getter ou un setter, etc. Ici, il suit:

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

Répondre

2

Peut-être que je m étant trop simpliste, mais ne suffirait-il pas d'ajouter une nouvelle propriété au SecretEntity partiel qui permet le cryptage et le décryptage? Vous pouvez rendre la propriété d'origine générée par LINQ à SQL interne:

public partial class SecretEntity 
{ 
    public string BigSecret 
    { 
     get { return Decrypt(this.BigSecretInternal); } 
     set { this.BigSecretInternal = Encrypt(value); } 
    } 
} 
+0

Cette réponse simplifie beaucoup trop les choses! ;) Sérieusement, je n'ai pas pensé à la propriété d'entité interne LINQ-to_SQL. Eh bien, au moins, je sais maintenant comment utiliser Castle Dynamic Proxy. Merci. Je voudrais toujours savoir d'un moyen de câbler mes entités avec des proxies dynamiques par intérêt. –

+0

@Jacques: Ça valait le coup d'essayer ;-). J'ai peur de ne pas pouvoir vous aider avec Castle Dynamic Proxy. – Steven