4

我有一个用户类,它的用户名需要加密保存在数据库中

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 时,它会变成这样: Select * from [dbo].[User] Where Username like 'Hamza'

正如您可能注意到的那样,表中没有名为用户名的列,而是securedusername,它包含加密值谁能帮我解决这个问题,我需要能够使用LINQ进行查询。

4

3 回答 3

1

您可以使用自定义类型来加密您的用户名(而不是在 User 类中进行加密,而是在自定义类型中进行加密)参见http://nhforge.org/blogs/nhibernate/archive/2009/02/22/加密密码或其他字符串在 nhibernate.aspx

当您查询时,您将只能查询完全匹配,但您将能够执行如下查询:

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

如果要不区分大小写匹配,可以在自定义类型中将值转换为大写/小写。

如果您想做 LIKE 搜索,那么您将需要查看其他类型的索引 - 例如。Lucene.NET 和 NHibernate.Search

于 2012-10-22T15:11:11.443 回答
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

于 2012-10-22T06:51:39.773 回答
0

我从未使用过NHibernate,但问题是Username 的定义是在模型中而不是在数据库中。

基本上你有两种选择(请记住,我从未真正使用过 NHibernate,而是其他实体框架/ORM),可能还有第三种选择,取决于 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 的特定实例进行包装,那将是一种解决方案。查看http://msdn.microsoft.com/en-us/library/bb351562.aspx了解 IQueryable 的描述。

但基本上,加密必须发生在服务器上,即不在数据库中,这有点限制了您的选择。

编辑: 搜索匹配“Hamz *”的所有用户,我们必须加载到内存并在那里检查:

var users = _session.QueryOver<User>().ToList().Where(x => x.Username.StartsWith("Hamz"));
于 2012-10-22T07:20:07.060 回答