简体   繁体   English

Visual C#对连接到Access Db的Login表单进行编程,仅给出尝试登录

[英]Visual C# Programming a Login form connected to a Access Db that gives only tries to log into

I am developing a login form in C#. 我正在用C#开发一个登录表单。 This form connects to the database to match the username and password and also to find any duplicate. 此表单连接到数据库以匹配用户名和密码,还可以查找任何重复项。 What I was trying to do is to implement a loop to accept only three tries then it will close. 我试图做的是实现一个循环以仅接受三个尝试,然后它将关闭。 The code is: 代码是:

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();
        }
    }
}

I have tried many solutions but I am still groping in the dark. 我尝试了许多解决方案,但我仍然在黑暗中摸索。 Any suggestions will be appreciated, cheers. 如有任何建议,我们将不胜感激。

Define a counter to store user's attempts: 定义一个counter来存储用户的尝试:

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

Then increment it each time user type invalid password or username : 然后,每当用户键入无效的passwordusername时,将其递增:

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

Then before you check whether or not the user exists, first check the counter and perform appropriate action: 然后,在检查用户是否存在之前,首先检查计数器并执行适当的操作:

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

There are a few helpfull answers, but I prefered to have one correct example. 有一些有用的答案,但我更喜欢举一个正确的例子。 Your code has a few problems 您的代码有一些问题

  • It's easy to hack your database using SQL Injection 使用SQL Injection入侵数据库很容易
  • There are some issues with IDisposable, which can create memory leaks. IDisposable存在一些问题,可能会导致内存泄漏。
  • The code is very tight coupled to the frontend, which is almost always the case in winforms. 该代码与前端紧密耦合,在winforms中几乎总是这样。 Nevertheless I prefer to limit the calls to the UI Components. 尽管如此,我还是希望将调用限制为UI组件。

The code I've is the following: (it has inline comments) 我的代码如下:(具有内联注释)

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);
    }
}

For your initial question I've finished the answer of Selman22, basicly I've used a private field which keeps track of the number of failed tries. 对于您的第一个问题,我已经完成了Selman22的回答,基本上,我使用了一个私有字段来跟踪失败尝试的次数。 Each time the user tries to login, we check if its the 3th time. 每次用户尝试登录时,我们都会第三次检查。 If so we close the form. 如果是这样,我们关闭表格。

This still isn't the best approach imho, but I didnt want to change your context ;-) 恕我直言,这仍然不是最好的方法,但是我不想更改您的上下文;-)

I've also removed the SQL Injection possibilities by adding Parameters to the query. 通过将参数添加到查询中,我还删除了SQL注入的可能性。

To work with IDisposable implementations, you have to Dispose the object correctly. 要使用IDisposable实现,必须正确处理对象。 This is done in the finally block of the try/catch statement (or by a USING statement, like I did). 这是在try / catch语句的finally块中完成的(或像我一样通过USING语句)。

I hope this is helpfull, if not freel free to comment. 我希望这是有帮助的,如果不是随意发表评论的话。

Your current problem is quite simple, you need to maintain the number of login attempts outside of the btn_login_click method. 当前的问题非常简单,您需要在btn_login_click方法之外维护登录尝试的次数。 Create a private field outside of the method and initialize it to 0, increment it in the click handler and stop when it's X. But I'm not sure that is sufficient--typically, you want something to not only limit the number of attempts sequentially, but to limit the number of attempts in total and/or for a specific username. 在方法之外创建一个私有字段,并将其初始化为0,在点击处理程序中将其递增,然后在X处停止。但是我不确定是否足够,通常,您希望不仅限制尝试次数顺序,但限制总数和/或特定用户名的尝试次数。

Also your current code is subject to SQL injection and is poorly structured (the validation and query code should not be in the click event handler). 另外,您当前的代码会受到SQL注入的影响,并且结构不正确(验证和查询代码不应位于click事件处理程序中)。

NOTE: Your code is storing the password directly in the database, this is a BIG "No-NO" . 注意:您的代码将密码直接存储在数据库中,这是BIG“ No-NO” You always store just a hash of the password, never the password itself. 您始终只存储密码的哈希值,而不存储密码本身。 Even if you need the set the password automatically and then send it to the user -- there's really no reason to store the password directly instead of storing a hash of the password. 即使您需要自动设置密码然后再将其发送给用户,实际上也没有理由直接存储密码而不是存储密码的哈希值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 连接到 MS Access 数据库 2000 - 2003 格式的 Visual Studio C# windows 窗体中的登录功能。 研究并尝试修复无济于事 - login function in a visual studio C# windows form connected to a MS Access database 2000 - 2003 format. Researched and tried fixing to no avail 在Visual C#Express中连接Access数据库 - Connecting Access db in Visual C# express 使用连接到MS Access数据库的C#中的用户角色登录 - login with user roles in C# connected to MS Access database 如何通过访问数据库在visual studio c#中仅验证注销一次 - how to validate log out only once in visual studio c# via access database TreeView,Access DB和Windows窗体(C#) - TreeView, Access DB & Windows Form (C#) C#:当我运行程序并且Visual Studio尝试创建一个新类时,第二个表单没有加载? - C#: Second form is not loading when I run the program and Visual Studio tries to create a new class? c# 如何关闭应用程序。 在 3 次错误的登录尝试后 - c# how to close app. after 3 wrong login tries c#登录注册表单仅注册用户详细信息1次 - c# login registration form registers user details only 1 time 如何从C#中的其他表单访问可视组件 - How to access a visual component from another form in c# 使用C#从Visual Studio中的其他表单访问变量 - Access variable from another form in Visual Studio with c#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM