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();
}
}
}
Я перепробовал множество решений,но все еще блуждаю в темноте. Любые предложения будут оценены, ура.
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