ASP.net(C#)中的字符串比较

5

我正在编写一个连接ASP.net web service(C#,3.5)的Android应用程序。

Android应用程序将用户的“登录”信息发送到Web服务,以验证用户是否注册。

这里是接收请求的[WebMethod]

[WebMethod]
public SigninPerson signin(SigninPerson SIPerson)
{
    SigninPerson Temp = new SigninPerson(0, "", "", "", "");
    LinqToSQLDataContext DataBase = new LinqToSQLDataContext();
    var Person = (from a in DataBase.Persons
                  where a.Email == SIPerson.E_Mail &&
                      a.Password.Equals(SIPerson.Password,StringComparison.Ordinal)
                  select new SigninPerson
                  {
                      Person_Id = a.Person_Id,
                      F_Name = a.First_Name,
                      L_Name = a.Last_Name,
                      E_Mail = a.Email,
                      Password = a.Password
                  });
    if (Person.Any() == true)
    {
        Temp = Person.FirstOrDefault();
    }
    return Temp;
}

SigninPerson是一个类,用于保存用户信息,如名字、姓氏、密码等。

问题出在密码比较上。它接受了所有的情况。

例如:

如果数据库中某人的密码是"ABD",而用户输入"abd"作为密码,应用程序会接受它!(不区分大小写!)

如何解决这个问题?


请查看此链接:http://msdn.microsoft.com/zh-cn/library/vstudio/cc165449.aspx - Alex
1
@Alex:不过还是有点奇怪,因为StringComparison.Ordinal应该是区分大小写的(否则,他应该使用StringComparison.OrdinalIgnoreCase)。 - Dan
4
问题在于 SQL Server 不进行序数比较。 - Mike Perrenoud
是的,neoistheone 完全正确。 - Alex
1
你应该对密码进行哈希处理,而不是以明文形式存储它们。 - Mansfield
2个回答

4

将您的LINQ修改为以下内容:

var Person = (from a in DataBase.Persons
              where a.Email == SIPerson.E_Mail
              select new SigninPerson
              {
                  Person_Id = a.Person_Id,
                  F_Name = a.First_Name,
                  L_Name = a.Last_Name,
                  E_Mail = a.Email,
                  Password = a.Password
              })
              .ToList()
              .Where(sp => sp.Password.Equals(SIPerson.Password));

这将通过.NET框架在客户端强制进行字符串比较,而不是在SQL Server上在服务器端进行。


如andleer所述,还有另一种可能更有效的方法。现实情况下,你不太可能看到这种情况,但养成这个好习惯是很有必要的。你可以这样做:

var Person = (from a in DataBase.Persons
              where a.Email == SIPerson.E_Mail
              select new SigninPerson
              {
                  Person_Id = a.Person_Id,
                  F_Name = a.First_Name,
                  L_Name = a.Last_Name,
                  E_Mail = a.Email,
                  Password = a.Password
              })
              .Take(1)
              .AsEnumerable()
              .Where(sp => sp.Password.Equals(SIPerson.Password));

这样做应该确保它永远不会返回所有的行,而只是1行。再次强调,在实际情况下可能并不那么重要,因为几乎肯定只有一行 - 但这是一个很好的想法可以添加并值得注意。

1
简单。好的解决方案。 - andleer
3
实际上,一个更好的解决方案是:不用 ToList(),改用 .Take(1).AsEnumerable()。如果查询匹配了1000条记录,你只需要知道零条或一条记录就可以满足 Any() 的条件。 - andleer
@andleer:如果它匹配超过一个记录,那么就存在相当严重的逻辑问题。我期望电子邮件应该是唯一的。 - musefan
@neoistheone 在本地运行正常,但是当我将项目上传到smarterasp.net后问题又出现了:(为什么? - Mohamad Ghanem
1
@MGCR7,我不确定。我得想一想。但是现在感觉应该需要回收应用程序池。 - Mike Perrenoud
显示剩余5条评论

1
问题在于,除非已经配置,否则SQL不会执行区分大小写的匹配,这里有更多信息
或者,在获得匹配项后,您可以通过代码进行检查:
不要使用if (Person.Any()),而是使用以下内容:
var first = Person.FirstOrDefault();
if (first != null && first.Password == SIPerson.Password)
{
    Temp = first;
}

抱歉,但您的前提并不总是正确的。SQL 根据配置时设置的排序选项执行大小写比较。它可能是大小写敏感的,也可能不是。此外,排序规则可以在服务器、数据库或列级别上设置。 - andleer
@andleer:是的,我说过了,我没有使用“排序”这个词,但是在我发布的链接中有描述。 “似乎您可以将某些字段设置为区分大小写处理”=更改排序方式,如链接所述。 - musefan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接