C# - 多个if else语句无法正常工作

时间:2011-12-05 12:09:43

标签: c# mysql if-statement

我正在使用mysql的.net连接器。我去编写了一个用户登录表单代码,这似乎工作正常,但是当我点击登录按钮并提供有效的登录详细信息时,它告诉我我已成功登录然后告诉我它的用户/通行证组合错误。

这里是代码,一切似乎都应该如此。

程序检查散列密码与数据库中输入的密码,这一切都很好用。但由于某种原因,“成功登录”消息框随后显示,“错误的用户名/密码组合”消息框显示。

我一直想弄清楚过去两天我哪里出错了,它让我疯了。也许你们可以看到我搞砸的地方lol

代码:

            try
        {
            MySqlConnection connection = new MySqlConnection(MyConString);
            MySqlCommand command = connection.CreateCommand();
            MySqlDataReader Reader;
            command.CommandText = "select * from users";
            try
            {
                connection.Open();
            }
            catch (Exception ex)
            {
                listBox4.Items.Add(ex);
                MessageBox.Show("There has been an error connecting to the user database! Please try again later.");
            }
            Reader = command.ExecuteReader();
            while (Reader.Read())
            {
                if (textBox4.Text == Reader.GetString(2))
                {
                    string haspass= CryptorEngine.Encrypt(textBox5.Text, true);
                    if (haspass == Reader.GetString(3))
                    {
                            MessageBox.Show("Successfully logged in!");
                    }
                    else
                    {
                        MessageBox.Show("Wrong Unhashed Username/Password Combination");
                    }
                }
                else
                {
                    MessageBox.Show("Wrong Username/Password Combination");
                }
            }
            connection.Close();
        }
        catch (Exception ex)
        {
            listBox4.Items.Add(ex);
        }

8 个答案:

答案 0 :(得分:4)

看起来你的DataReader正在返回多个结果,代码会进入第一个结果的成功路径,然后是第二个结果的不成功路径。

您需要使您的SQL更具体,而不是查询所有用户select * from users您应该只查询尝试登录的用户的详细信息,例如(伪代码) -

select * from users where username = yourusernamefield

从表单中获取yourusernamefield值。您需要通过将用户名字段作为参数传递给查询来防止SQL注入。

答案 1 :(得分:3)

这是一种更好的方法:

try
{
    MySqlConnection connection = new MySqlConnection(MyConString);
    MySqlCommand command = connection.CreateCommand();
    MySqlDataReader Reader;
    //Change the "username" and "password" to the corresponding names of these columns in your table
    command.CommandText = "SELECT * FROM users WHERE username = @username AND password = @password LIMIT 1";
    //assuming textbox4 has the username
    command.Parameters.AddWithValue("@username", textBox4.Text); 
    command.Parameters.AddWithValue("@password", CryptorEngine.Encrypt(textBox5.Text, true));

    try
    {
        connection.Open();
    }
    catch (Exception ex)
    {
        listBox4.Items.Add(ex);
        MessageBox.Show("There has been an error connecting to the user database! Please try again later.");
        //you should return here since if there's no connection you can't run the query
    }

    Reader = command.ExecuteReader();

    if(Reader.HasRows){
        MessageBox.Show("Successfully logged in!");
    }
    else
    {
        MessageBox.Show("Wrong Username/Password Combination");
    }

    connection.Close();
}
catch (Exception ex)
{
    listBox4.Items.Add(ex);
}

这只会返回一行(如果存在)。

答案 2 :(得分:1)

您正在遍历表格中的每个用户,当然会有一个用户的凭据不匹配。

尝试将凭据添加到您的查询中,例如:

command.CommandText = "select * from users where username = ?username AND password = ?password";
IDbDataParameter usernameParameter = _command.CreateParameter();
usernameParameter.ParameterName = "?username";
usernameParameter.Value = username;
command.Parameters.Add(usernameParameter);
IDbDataParameter passwordParameter = _command.CreateParameter();
passwordParameter .ParameterName = "?password";
passwordParameter .Value = password;
command.Parameters.Add(passwordParameter);

然后,如果找到匹配项,则表示凭据正确无误。

顺便说一下,如果在调用connection.Close()之前抛出异常,可能不会关闭连接,考虑在finally块中添加Close调用,或者在using块中使用您的连接像这样:

using (MySqlConnection connection = new MySqlConnection(MyConString))
{
  ...
}

答案 3 :(得分:1)

您正在查询所有用户,并测试所有用户,并在每个用户上发送消息。如果可能,您应该使用用户名select限制原始where

作为观察,在理想情况下,您将在用户记录上使用“salt”,并在哈希中使用它(以防止通过彩虹表或其他非用户特定方法中断)。例如,如果这是我,我会有类似的东西(为了简洁起见使用“dapper”语法):

string name = ... // whichever text.Text
string pw = ...
var row = connection.Query("select Salt, Hash from Users where Username = @name",
          new {name}).SingleOrDefault();
bool loggedIn = false;
if(row != null)
{
    byte[] salt = row.Salt, hash = row.Hash;
    loggedIn = BlobsAreEqual(CryptorEngine.Encrypt(pw, salt, true), hash);
}
// maybe add random wait here, to slow down brute-force
if(loggedIn) {
   // great!
} else {
   // increment failed counter, and potentially lock out account
}

答案 4 :(得分:0)

作为一个直接的解决方案,您应该在成功的消息后立即返回。似乎正在发生的是您遍历用户,首先遇到正确的用户帐户,然后在下一次迭代中遇到另一个用户。

要正确解决问题,您可以使用以下代码替换代码:

try
{
    using(MySqlConnection connection = new MySqlConnection(MyConString))
    using(MySqlCommand command = connection.CreateCommand())
    {
        command.CommandText = 
            @"SELECT CASE WHEN EXISTS (
                SELECT * from users 
                WHERE USERNAME = @Username AND Password = @Password
                LIMIT 1) THEN 1 ELSE 0 END";

        try { connection.Open(); }
        catch (Exception ex)
        {
            listBox4.Items.Add(ex);
            MessageBox.Show("There has been an error connecting to the user database! Please try again later.");
        }

        command.Parameters.AddWithValue("@Username", textBox4.Text);
        command.Parameters.AddWithValue("@Password", 
            CryptorEngine.Encrypt(textBox5.Text, true));

        Successful = (int) command.ExecuteScalar() == 1;
        MessageBox.Show(Successful
            ? "Successfully logged in!"
            : "Wrong Username/Password Combination");
    }
}
catch (Exception ex)
{
    listBox4.Items.Add(ex);
}

上面的代码将查询限制为单个结果,并允许您使用连接器的参数化工具来避免潜在的SQL注入攻击并快速断言用户的身份。

编辑: EXISTS documentation

EXISTS回答给定子查询是否返回结果。我使用它来确保查询尽可能优化,并避免表扫描。 EXISTS将忽略子查询中的选择列表,并且一旦确定可以获得给定子查询的任何结果,就会立即返回。 LIMIT在这个例子中可能是多余的,但我不完全确定。

答案 5 :(得分:0)

这两行:

command.CommandText = "select * from users";

while (Reader.Read())
{

}

您正在从数据库中读取所有用户,并循环显示所有返回的项目。然后你有:

if (textBox4.Text == Reader.GetString(2))
{
    ....
}
else
{
    MessageBox.Show("Wrong Username/Password Combination");
}

使用此代码,您将为每个不是您在输入框中输入的用户打印出“错误的用户名/密码”消息。

您可以只查找输入表单的特定用户:

command.CommandText = "select * from users where username = @username";
command.Parameters.AddWithValue("@username", textBox4.Text);

或只打印一条错误消息:

bool loggedIn = false;
while (Reader.Read())
{
    if (textBox4.Text == Reader.GetString(2))
    {
        string haspass= CryptorEngine.Encrypt(textBox5.Text, true);
        if (haspass == Reader.GetString(3))
        {
            loggedIn = true;
        }
    }
}

if (loggedIn)
{
    MessageBox.Show("Successfully logged in!");
}
else
{
    MessageBox.Show("Wrong Unhashed Username/Password Combination");
}

虽然你可以更好地构建它。

事实上,如果您同时发送用户名和密码,您可以一次性完成检查。如果没有该名称的用户或密码不正确,则不会返回任何结果,但如果组合正确,则只有一个结果,您将知道该用户无效而无需进一步操作检查。

答案 6 :(得分:0)

在代码中,您有:command.CommandText = "select * from users"因此对于您尝试登录的数据库中的每个用户。 Probaly有2个用户,您的登录数据可以用于其中一个用户。您应该在成功之后从函数返回,并且仅在没有用户成功时显示失败。

答案 7 :(得分:0)

循环遍历所有用户。凭证与第一个凭证匹配,您可以“登录”,下一个凭据失败。

相关问题