2012-10-22 121 views
4

我有了用戶名的用戶類,我需要在數據庫中保存加密查詢使用LINQ

public abstract class User 
{ 
    public virtual int Id { get; protected set; } 
    public virtual string Username 
    { 
     get 
     { 
      return _encryptionProvider.Decrypt(SecuredUsername); 
     } 
     protected set 
     { 
      SecuredUsername = _encryptionProvider.Encrypt(value); 
     } 
    } 
    [Obsolete("Use the 'Username' property -- this property is only to be used by NHibernate")] 
    protected virtual string SecuredUsername { get; set; } 
} 

我映射爲下面的用戶實體加密值:

public class UserMapping : ClassMap<User> 
{ 
    public UserBaseMapping() 
    { 
     Id(user => user.Id).GeneratedBy.HiLo("100"); 
     Map(Reveal.Member<UserBase>("SecuredUsername")).Unique(); 
    } 
} 

它的工作很好,直到我不得不寫一些LINQ語句。

User user = _session.QueryOver<User>().Where(x => x.Username == "Hamza").SingleOrDefault(); 

這裏的問題是,當LINQ翻譯上面的語句到SQL變成是這樣的:從[DBO] 選擇* [用戶]哪裏像「哈姆扎」

而作爲用戶名,你可能注意到表中沒有名爲username的列,但securedusername並且包含加密值 任何人都可以請我幫忙解決這個問題,我需要能夠使用LINQ進行查詢。

+0

首先,您的代碼不支持此搜索要求。您的代碼只能搜索用戶是否給出了整個用戶名。你必須尋找[this]這樣的東西,但這不是nhibernate。但是這必須是這樣的。但這不是nhibernate(http://stackoverflow.com/questions/835790/how-to-do-sql-like-in-linq) –

回答

0

這個怎麼樣:

User user = _session.QueryOver<User>().Where(x => x.securedusername == _encryptionProvider("Hamza")).SingleOrDefault(); 

編輯: 正如我已經在評論上述你的查詢有問題。 一種選擇是,(只有在用戶名是唯一的,否則可能會發生衝突時才能完成) 1.您必須提供一個對每個字符串值唯一的索引。 爲EX:

SAM = xyz(110111101) 
SAMI = xyzk(110111101001) 

該指數必須插入數據庫中的每一位客戶。

那麼你可以去像:

`User user = _session.QueryOver<User>().Where(x => x.Index.Contains(IndexGenerator("Hamza"))).SingleOrDefault();//I do not know weather this Contains method exist in nhibernate`. But there should be. so find that :) 

但這個查詢將給一些不必要的值爲好,但可使用的編碼解碼後的實際用戶名進行進一步篩選。這可以獲得精確的搜索結果。

如果模糊不清,您可以使用此IndexGenerator作爲您的_encryptionProvider

+0

我想到了,但這不會起作用的情況下開始或結束甚至搜索部分字符串 另外我不希望LINQ擔心加密和解密值 – Hamza

+0

爲什麼要加密用戶名並將其保存在數據庫中。直觀地規範其被加密的密碼。 –

+0

但我不知道你的要求,這就是爲什麼有2件事1.用戶名2.密碼。我不希望LINQ擔心加密和解密值。那麼你將如何使用LINQ插入到這個用戶表中。儘管如此,我仍然可以與您一起尋找答案,但「在字符串的開頭或結尾處甚至搜索部分字符串」能否在您的評論中解釋此引用。 –

0

我從來沒有使用NHibernate,但問題是,用戶名的定義是在模型中,而不是在數據庫中。

基本上,你有兩個選擇(記住,我從來沒有實際使用NHibernate,但其他實體框架/ ORMs),可能有三分之一取決於NHibernate的IQueryable的實現。

加載整個表到內存(如果是小,你做這個查詢往往可能是有用的,因爲我想NHibernate的有一些智能緩存):

User user = _session.QueryOver<User>().ToList().FirstOrDefault(x => x.Username == "Hamza"); 

二是檢查對加密的字符串,如@Diode提供:

// Resolve string, since we are using LINQ2SQSL in some form 
var encName = _encryptionProvider.Encrypt("Hamza"); 
User user = _session.QueryOver<User>().FirstOrDefault(x => x.SecuredUsername == encName); 

如果您可以使用IQueryable的特定實例用於包裝的目的,那將是一個解決方案。有關IQueryable的說明,請參閱http://msdn.microsoft.com/en-us/library/bb351562.aspx

但基本上,加密必須發生在服務器上,即不在數據庫中,這種限制您的選擇。

編輯: 搜索匹配「Hamz *」的所有用戶,我們需要加載到內存,並檢查有:

var users = _session.QueryOver<User>().ToList().Where(x => x.Username.StartsWith("Hamz")); 
+0

感謝您的文章,但二極管的解決方案的問題是,如果我想搜索字符串的一部分讓我們說,讓所有的用戶現在他們的用戶名以「火腿」開頭,如果我使用這種方式,那麼肯定_encryptionProvider(「火腿」)與_encryptionProvider沒有任何關係( 「Hamza」),所以不能搜索字符串的一部分 – Hamza

+0

@Hamza我添加了一個編輯,如果這是您想要的功能,您必須將tabel加載到內存並在那裏解密。 IE瀏覽器不會很快只用數據庫與SQL。 – flindeberg

+0

這將工作,如果我只有一個表具有加密值,但我的客戶需要我加密大約5個表中的數據並將表加載到內存並解密它fr每個請求將是非常昂貴的性能 – Hamza

1

您可以使用自定義類型,加密您的用戶名(而不是做在用戶級加密,做自定義類型的加密)看到http://nhforge.org/blogs/nhibernate/archive/2009/02/22/encrypting-password-or-other-strings-in-nhibernate.aspx

當您查詢,您將只能夠查詢完全匹配,但你可以做這樣的查詢:

User user = _session.QueryOver<User>() 
    .Where(x => x.Username == "Hamza") 
    .SingleOrDefault(); 

如果要以不區分大小寫的方式進行匹配,可以將該值在自定義類型中轉換爲大寫/小寫。

如果你想做LIKE搜索,那麼你將需要看看其他類型的索引 - 例如。 Lucene.NET和NHibernate.Search

+0

我做過了,但是同樣的問題,我的問題是如何使用加密值LINQ不是使用nhibernate加密/解密數據的機制 – Hamza

+0

爲什麼你需要加密值?使用Nhibernate,數據的加密持久性對於您的使用來說變得透明(在合理範圍內),因此您不需要訪問加密的數據 –