ADODB.Command,查找满足条件的行

时间:2020-10-18 16:42:56

标签: c# sql database adodb

该工作在C#中完成,并带有一个Access数据库进行连接。 目前,我想从表ACCOUNT_T中检索满足用户输入的凭据(用户名,电子邮件,密码)的帐户数。

该表具有3个属性:acc_username VARCHAR(30),acc_email VARCHAR(50)和acc_password VARCHAR(30) 该表只有一个主菜:“ Tester”,“ test@mail.com”,“ TestPass”

我想检查数据库中与用户输入的凭据匹配的行数/主目录数(每个帐户都是唯一的,因此假设没有重复),并使用了下面显示的代码。

//Checks whether the user has entered the correct credentials
//If correct info is entered, redirect user to the Main Menu page
private void Login_Login_Button_Click(object sender, EventArgs e)
{
    //Open connection
    ADODB.Connection connection = new ADODB.Connection();
    connection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=main_db;Jet OLEDB:Engine Type=5;";
    connection.Open();

    //Create command and object
    ADODB.Command command = new ADODB.Command();
    object rowsAffected;

    //Setting up command and parameters
    command.ActiveConnection = connection;
    command.CommandText = "SELECT COUNT(*) FROM ACCOUNT_T WHERE acc_username = \'@USERNAME\' AND acc_email = \'@EMAIL\' AND acc_password = \'@PASSWORD\'";
    command.Parameters.Append(command.CreateParameter("@USERNAME", DataTypeEnum.adVarChar, ParameterDirectionEnum.adParamInput, 200, Login_Username_TextBox.Text));
    command.Parameters.Append(command.CreateParameter("@EMAIL", DataTypeEnum.adVarChar, ParameterDirectionEnum.adParamInput, 200, Login_Email_TextBox.Text));
    command.Parameters.Append(command.CreateParameter("@PASSWORD", DataTypeEnum.adVarChar, ParameterDirectionEnum.adParamInput, 200, Login_Password_TextBox.Text));

    //Execute command and store into RecordSet
    ADODB.Recordset recordSet = command.Execute(out rowsAffected);
    //Output A
    MessageBox.Show(recordSet.RecordCount.ToString());
    //Output B
    MessageBox.Show(((int)rowsAffected).ToString());

    connection.Close();

    if ((int)rowsAffected == 1)
    {
        MainMenu_User_Label.Text = "Logged In As: " + Login_Username_TextBox.Text;
        SetupPanel(MainMenu_Panel);
    }
    else
    {
        MessageBox.Show("Wrong Credentials.", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

但是,如上所述,输出A的“ recordSet.RecordCount.ToString()”的值为-1,输出B的“((int)rowsAffected).ToString()”的值为0。无论用户输入是对还是错,输出都是相同的。 (意味着无论用户输入的数据是否已经存在于数据库中,都会给出相同的输出)

代码是否有问题?

1 个答案:

答案 0 :(得分:0)

private string ConnectionString {get { return "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=main_db;Jet OLEDB:Engine Type=5;"; } };

private void Login_Login_Button_Click(object sender, EventArgs e)
{
    string sql = "
        SELECT COUNT(*) 
        FROM ACCOUNT_T 
        WHERE acc_username = ? AND acc_email =  ? AND acc_password = ?";

    int rowsAffected = 0;
    using (var connection = new OleDbConnection(ConnectionString))
    using (var command = new OleDbCommand(sql, connection))
    {
        // Use OleDbType enum values to match database column types and lengths.
        // I have to guess, but you can get exact values from your database.
        // Also, OleDb uses positional parameters, rather than names.
        // You have to add the parameters in the order they appear in the query string.
        command.Parameters.Add("acc_username", OleDbType.VarChar, 200).Value = Login_Username_TextBox.Text;
        command.Parameters.Add("acc_email", OleDbType.VarChar, 200).Value = Login_Email_TextBox.Text;
        command.Parameters.Add("acc_password", OleDbType.VarChar, 200).Value = Login_Password_TextBox.Text;

        cn.Open();
        rowsAffected = (int)command.ExecuteScalar();
    } //leaving the using block will guarantee the connection is closed, even if an exception is thrown

    MessageBox.Show(rowsAffected.ToString());

    if (rowsAffected == 1)
    {
        MainMenu_User_Label.Text = "Logged In As: " + Login_Username_TextBox.Text;
        SetupPanel(MainMenu_Panel);
    }
    else
    {
        MessageBox.Show("Wrong Credentials.", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

虽然我在这里,但我还需要提到这是非常差的密码处理。甚至对于简单的个人应用程序或测试应用程序,都无法永远存储这样的密码。即使在学习代码时,这也是做错了太重要的事情之一。问题是人们倾向于重复使用密码,因此,对您简单的测试应用程序的破坏也可能为攻击者提供凭据,从而使他们可以访问更重要的内容。 不要这样做。

相反,您必须为每个用户创建一个唯一的salt(或nonce)值。当用户设置密码时,您将盐添加到新密码之前。然后,使用诸如BCrypt之类的算法创建组合值的加密哈希,然后再次将salt附加到最终值。现在,您仅存储此更改的信息。 从不存储实际密码。当有人尝试登录时,您将检索存储的信息,提取盐,然后对尝试的密码使用相同的过程。现在,您可以比较散列值,而不是原始密码。