【问题标题】:ADODB.Command, finding rows that satisfy a conditionADODB.Command,查找满足条件的行
【发布时间】:2021-02-01 13:09:22
【问题描述】:

这项工作是在 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。无论用户输入是对还是错,输出都是相同的。 (意思是无论用户输入的数据是否已经在数据库中,都给出相同的输出)

代码有问题吗?

【问题讨论】:

  • 不要将参数放在引号中。
  • @LarsTech 您指的是 CommandText 字符串中的引号,还是参数本身?就像,我是否将其设为“从 ACCOUNT_T 中选择 COUNT(*),其中 acc_username = USERNAME AND acc_email = EMAIL AND acc_password = PASSWORD”? (不确定如何在不触发 StackOverflow 中的用户名的情况下插入 @,假设它们是在 USERNAME、EMAIL 和 PASSWORD 之前添加的)尝试了那个,但没有用。
  • 这只是... acc_username = @USERNAME AND ... 您使用过时技术的任何原因?你应该更喜欢 ADO.Net。
  • @LarsTech 我是 C# 编程和数据库的新手,所以没有意识到 ADODB 已经过时了。然后将研究 ADO.Net。谢谢。

标签: c# sql database adodb


【解决方案1】:
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);
    }
}

虽然我在这里,但我还需要提到这是非常糟糕的密码处理。 绝不可以存储这样的密码,即使对于简单的个人或测试应用程序也是如此。即使在学习代码时,这是一件非常重要的事情,不能做错。问题是人们倾向于重复使用密码,因此对您的简单测试应用程序的破坏也可能为攻击者提供凭据,从而授予对更重要的东西的访问权限。 不要这样做。

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

【讨论】:

    猜你喜欢
    • 2013-10-19
    • 2019-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-11
    • 2021-05-15
    • 1970-01-01
    相关资源
    最近更新 更多