【问题标题】:Check if username/password exists in multiple tables检查用户名/密码是否存在于多个表中
【发布时间】:2015-01-31 12:53:56
【问题描述】:

我正在处理登录页面。我想检查数据库中是否存在用户名和密码。我有三个数据库表:Teams、Organizers、Admins,每个表中分别带有用户名和密码字段。我正在实现三层架构中的登录。

我认为下面的 SQL 语句 有问题。我使用不同/有效的团队用户名和团队密码测试了我的 sql 查询。 COUNT 查询返回多行,不正确。

这是我的数据访问层代码:

 public int getExistingAccount(string username, string password)
    {
        string queryStr = "SELECT COUNT(*) FROM Teams t,Organizers o,Admins a WHERE (t.teamUsername=@username AND t.teamPassword=@password) OR (o.organizerUsername=@username AND o.organizerPassword=@password) OR (a.adminUsername=@username AND a.adminPassword=@password)";

        SqlConnection conn = new SqlConnection(_connStr);
        SqlCommand cmd = new SqlCommand(queryStr, conn);
        cmd.Parameters.AddWithValue("@username", username);
        cmd.Parameters.AddWithValue("@password", password);

        int returnValue = 0;

        conn.Open();
        returnValue = (int)cmd.ExecuteScalar();

        conn.Close();
        return returnValue;

    }

至于业务逻辑层代码:

public string getAccount(string username, string password)
    {
        string returnMessage = "";

        if (username.Length == 0)
            returnMessage += "Username cannot empty</br>";

        if (password.Length == 0)
            returnMessage += "Password cannot be empty</br>";

        if (username.Equals(password))
        {
            returnMessage += "Duplicate value. Please try again</br>";
        }

        //Invoke validateInput() method to validate data
        if (returnMessage.Length == 0)
        {
            int noOfRows = 0;

            LogAccounts logInd = new LogAccounts();
            noOfRows = logInd.getExistingAccount(username, password);

            if (noOfRows > 0)
                returnMessage += "Account found";
            else
                returnMessage += "Invalid username/password.";
        }

        return returnMessage;
    }

【问题讨论】:

  • 如果将 count(*) 替换为 * 会发生什么情况,是否得到预期的行?
  • 没有。它不返回预期的行
  • SELECT COUNT(*) FROM ( SELECT t.teamUsername as username FROM Teams t WHERE t.teamUsername=@username AND t.teamPassword=@password UNION SELECT o.organizerUsername as username FROM Organizers o WHERE o .organizerUsername=@username AND o.organizerPassword=@password UNION SELECT a.adminUsername as username FROM Admins a WHERE a.adminUsername=@username AND a.adminPassword=@password)
  • 提供一些示例数据和预期输出。你真的应该考虑重新设计。您应该使用所有用户所在的单个用户表,然后从 Teams/Organizers/admin 表中引用它。您应该遵循 C# 命名约定,并使用 CamelCase,而不是使用 lowerCamelCase 的 Java 约定。
  • 附带说明,您应该使用强大的算法(例如bcrypt)对存储在数据库中的密码进行散列和加盐处理。

标签: c# sql asp.net login three-tier


【解决方案1】:

试试这个,从每个表中选择并 UNION ALL 结果,然后计算行数。

select count(*) from
(
SELECT 1 as dummyname FROM Teams t
WHERE (t.teamUsername=@username AND t.teamPassword=@password)
union all
SELECT 1 FROM Organizers o
WHERE (o.organizerUsername=@username AND o.organizerPassword=@password)
UNION ALL
select 1 from Admnis
WHERE (a.adminUsername=@username AND a.adminPassword=@password)
)

【讨论】:

    【解决方案2】:

    我觉得你的数据库设计很笨拙,获取单个用户需要异常大/长的 sql 查询。

    在几乎每个用例中,您都会有一个用户表,如果您需要将用户与一些附加信息联系起来,您可以通过UserId 引用用户表。您还应该阅读外键。

    快速示例:

    Users:
    
    - UserId (int or guid) (primary key)
    
    - .... (additional fields removed for brewity)
    

    其他表将引用UserId 列,并使用它来提取有关具有连接的用户的信息。

    例如:SELECT T.*, U.* FROM Teams T INNER JOIN Users U ON U.UserId = T.UserId WHERE U.Username = "AwesomeCoach";

    一个简单的验证查询应该是这样的:

    SELECT COUNT(*) FROM Users WHERE Username = xx AND Password = xx

    这将返回一个integer,指定与给定用户名/密码组合匹配的行数。它应该是 1 或 0。在 Username 列上放置一个 Unique 约束,以确保每个 Username 仅出现一次。

    脚注:我看到您已经得到了解决您所面临问题的答案,但我建议您阅读一些数据库设计,并尽量保持简单。随着应用程序的增长,跨多个表管理多个用户可能而且将会很麻烦。

    【讨论】:

      【解决方案3】:

      你的设计真的很糟糕,你应该把所有用户都放在一张桌子上。之后,如果您想通过 id 获取用户,您应该检查 3 个差异表。无论如何,问题出在查询中,您应该这样写:

      string queryStr = @"
      SELECT 
          COUNT(*) AS TeamsCount,
          (SELECT COUNT(*) Organizers WHERE organizerUsername=@username AND organizerPassword=@password) AS OrgCount,
          (SELECT Count(*) Admins WHERE adminUsername=@username AND adminPassword=@password) AS AdminCount
      FROM 
         Teams 
      WHERE 
         teamUsername=@username AND 
         teamPassword=@password";
      

      查询应该是这样的。之后,您需要在 DataSet 中返回它。你需要:

      DataSet dst = new DataSet();
      using(SqlAdapter adapter = new SqlAdapter(cmd))
      {
          adapter.Fill(dst);
      }
      

      在这种情况下,您将拥有包含 3 列的 dst。检查现有用户应该是:

      if(dst.Tables[0].Rows[0]["TeamsCount"] > 0 || 
           dst.Tables[0].Rows[0]["OrgCount"] > 0 ||
           dst.Tables[0].Rows[0]["AdminCount"] > 0)
      {
          //user already exist !
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-13
        相关资源
        最近更新 更多