Visual C# Программирование формы входа, подключенной к БД Access, которая выдает только попытки входа



Я разрабатываю форму входа в систему на языке C#. Эта форма подключается к базе данных, чтобы соответствовать имени пользователя и паролю, а также найти любой дубликат. То, что я пытался сделать, это реализовать цикл, чтобы принять только три попытки, после чего он закроется. Код такой:



namespace RoyalCollegeApp
{
public partial class Login : Form
{
public Login()
{
InitializeComponent();
}

private void Login_Load(object sender, EventArgs e)
{

}

private void btn_login_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txt_user.Text))
{
MessageBox.Show("Please type your Username");
txt_user.Focus();
return;
}

if (string.IsNullOrEmpty(txt_pass.Text))
{
MessageBox.Show("Please type your Password");
txt_pass.Focus();
return;
}

try
{
string constring = @"Provider=Microsoft.ACE.OLEDB.12.0;
Data Source=C:...Auth_Credentials.accdb;";
OleDbConnection conDataBase = new OleDbConnection(constring);
OleDbCommand cmdDataBase = new OleDbCommand("Select * from Auth_Credentials where
Username='"
+ this.txt_user.Text
+ "' and Password='"
+ this.txt_pass.Text
+ "';", conDataBase);
OleDbDataReader myReader;

conDataBase.Open();
myReader = cmdDataBase.ExecuteReader();

int count = 0;

while (myReader.Read())
{
count = count + 1;
}
if (count == 1)
{
MessageBox.Show("Login Successful");
this.Hide();
RCM RCM = new RCM();
RCM.Show();
this.Hide();
RCM.FormClosing += RCM_Closing;
}
else if (count > 1)
{
MessageBox.Show("Duplicate Username or Password");
}
else
{
MessageBox.Show("Username or Password do not match");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

private void RCM_Closing(object sender, FormClosingEventArgs e)
{
Application.Exit();
}
}
}


Я перепробовал множество решений,но все еще блуждаю в темноте. Любые предложения будут оценены, ура.
674   3  

3 ответов:

Есть несколько полезных ответов, но я предпочел бы иметь один правильный пример. В вашем коде есть несколько проблем

  • легко взломать вашу базу данных с помощью SQL-инъекции
  • Есть некоторые проблемы с IDisposable, которые могут привести к утечкам памяти.
  • Код очень тесно связан с интерфейсом, что почти всегда имеет место в winforms. Тем не менее я предпочитаю ограничивать вызовы компонентами пользовательского интерфейса.

У меня есть следующий код: (он имеет встроенный Комментарии)

private int _failedLoginCounter = 0;

private void btnLogin_Click(object sender, EventArgs e)
{
    var username = txtUsername.Text;
    var password = txtPassword.Text;

    if (string.IsNullOrEmpty(username))
    {
        MessageBox.Show("Please type your Username");
        txtUsername.Focus();
        return;
    }

    if (string.IsNullOrEmpty(password))
    {
        MessageBox.Show("Please type your Password");
        txtPassword.Focus();
        return;
    }

    // Seperate the login check and make it lously coupled from the UI (= do not refer to the UI elements, instead pass the values to a method)
    CheckLogin(username, password);
}

private void CheckLogin(string username, string password)
{
    try
    {
        string constring = @"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=C:\...\Auth_Credentials.accdb;";

        // You need to use a using statement since OleDbConnection implements IDisposable
        // more inf: http://msdn.microsoft.com/en-us/library/system.data.oledb.oledbconnection(v=vs.110).aspx
        using (OleDbConnection conDataBase = new OleDbConnection(constring))
        {
            // You need to use a using statement since OleDbCommand implements IDisposable
            // more info: http://msdn.microsoft.com/en-us/library/system.data.oledb.oledbcommand(v=vs.110).aspx
            using (OleDbCommand cmdDataBase = conDataBase.CreateCommand())
            {
                cmdDataBase.CommandText =
                    "SELECT * FROM Auth_Credentials WHERE Username=@username AND Password = @password";

                cmdDataBase.Parameters.AddRange(new OleDbParameter[]
                {
                    new OleDbParameter("@username", username),
                    new OleDbParameter("@password", password)
                });

                // Open database if not open
                if (conDataBase.State != ConnectionState.Open)
                    conDataBase.Open();

                var numberOrResults = 0;

                // You need to use a using statement since OleDbDataReader inherits DbDataReader which implements IDisposable
                // more info: http://msdn.microsoft.com/en-us/library/system.data.common.dbdatareader(v=vs.110).aspx
                using (OleDbDataReader myReader = cmdDataBase.ExecuteReader())
                {
                    while (myReader != null && myReader.Read())
                    {
                        numberOrResults++;
                    }
                }

                // If only one result was returned by the database => Succesful login
                if (numberOrResults == 1)
                {
                    MessageBox.Show("Login Successful");
                    this.Hide();
                }

                // If more than 1 result was returned by the database => Failed login
                // This is not a good idea, this situation should never occor.
                // Always make sure username + pass (or whatever you use for authentication) is unique.
                else if (numberOrResults > 1)
                {
                    MessageBox.Show("Duplicate Username or Password");
                    // increment the failed login counter
                    _failedLoginCounter++;
                }
                // No match was found in te database => Failed login
                else if (numberOrResults == 0)
                {
                    MessageBox.Show("Username or Password do not match");
                    // increment the failed login counter
                    _failedLoginCounter++;
                }
            }

        }

        // If the user has 3 failed login attempts on a row => close.
        if (_failedLoginCounter >= 3)
            this.Close();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Для вашего первоначального вопроса я закончил ответ Selman22, в основном я использовал частное поле, которое отслеживает количество неудачных попыток. Каждый раз, когда пользователь пытается войти в систему, мы проверяем, если его 3-й раз. Если да, то мы закрываем форму.

Это все еще не лучший подход ИМХО, но я не хотел менять ваш контекст ; -)

Я также удалил возможности SQL-инъекции, добавив параметры в запрос.

Для работы с IDisposable реализации, вы должны правильно распорядиться объектом. Это делается в блоке finally оператора try/catch (или с помощью оператора USING, как я сделал).

Я надеюсь, что это полезно, если не свободно комментировать.

Определите counter для хранения попыток пользователя:

public partial class Login : Form
{
    int counter = 0;
    ...
}

Затем увеличивайте его каждый раз, когда пользователь вводит недопустимый password или username:

else if (count > 1)
{
      MessageBox.Show("Duplicate Username or Password");
      counter++;
}
else
{
     MessageBox.Show("Username or Password do not match");
     counter++;
}

Затем, прежде чем проверить, существует ли пользователь, сначала проверьте счетчик и выполните соответствующее действие:

private void btn_login_Click(object sender, EventArgs e)
{
       if(counter == 3) this.Close();
       ...
}

Ваша текущая задача довольно проста, вам нужно поддерживать количество попыток входа вне метода btn_login_click. Создайте частное поле вне метода и инициализируйте его до 0, увеличьте его в обработчике кликов и остановите, когда он станет X. Но я не уверен, что этого достаточно-обычно вы хотите что-то не только ограничить количество попыток последовательно, но и ограничить количество попыток в целом и/или для конкретного имени пользователя.

Также ваш текущий код подлежит SQL-инъекция и плохо структурирована (код проверки и запроса не должен быть в обработчике событий click).

Примечание: ваш код хранит пароль непосредственно в базе данных, это большое "Нет-нет" . Вы всегда храните только хэш пароля, а не сам пароль. Даже если вам нужно установить пароль автоматически, а затем отправить его пользователю-нет никакой причины хранить пароль непосредственно вместо хранения хэша пароля.

Comments

    Ничего не найдено.