在 VB.net 中尝试登录失败后系统锁定

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15627866/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 12:58:52  来源:igfitidea点击:

System Lock after failed login attempts in VB.net

vb.netsecurityms-accessloginblock

提问by Rara Arar

I use this code for my login form:

我将此代码用于我的登录表单:

Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLogin.Click
    Dim ErrorCount As Integer = 0

    If (ErrorCount = 3) Then
        MessageBox.Show(" The System has been Lock ", " Error! ", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Form3.Show()
    Else

        Dim con As OleDbConnection = New OleDbConnection( _
                   "Provider=Microsoft.Jet.OLEDB.4.0;Data Source= UserPass.mdb;")
        con.Open()
        Dim str As String
        str = "SELECT * FROM UserPass WHERE Username='" & txtUsername.Text & "' AND Password='" & txtPassword.Text & "'"
        Dim cmd As OleDbCommand = New OleDbCommand(str, con)
        cmd.Parameters.AddWithValue("user", txtUsername.Text)
        cmd.Parameters.AddWithValue("pass", txtPassword.Text)
        Dim sdr As OleDbDataReader = cmd.ExecuteReader()
        ' It will be case sensitive if you compare usernames here.   
        If sdr.HasRows Then
            If sdr.Read Then
                If txtPassword.Text <> sdr("Password").ToString Or txtUsername.Text <> sdr("Username").ToString Then
                    MessageBox.Show(" Incorrect Username/Password. Login Denied ", " Error! ", MessageBoxButtons.OK, MessageBoxIcon.Error)
                    ErrorCount = ErrorCount + 1
                Else
                    MessageBox.Show(" You are now Logged In! ", " Welcome! ", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
                    frmOne.Show()
                    Me.Hide()
                End If
            End If
        Else
            MessageBox.Show(" Incorrect Username/Password. Login Denied ", " Error! ", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End If


        sdr.Close()
        con.Close()
    End If

What im trying to do is when the user fails to login to the system 3 times, the system will show another form that says the system is locked and the user needs to type in the password from the system to be able to try to log-in again. Kindly help please.

我试图做的是当用户登录系统失败 3 次时,系统将显示另一个表单,表示系统已锁定,用户需要从系统输入密码才能尝试登录 -再进去。请帮助。

im using ms access as database for the username and password

我使用 ms access 作为用户名和密码的数据库

回答by user1937198

Combination of two of the other answers. You need to change the declaration to static so that it maintains state. Dim ErrorCount As Integer = 0to Static ErrorCount As Integer

结合其他两个答案。您需要将声明更改为静态以保持状态。Dim ErrorCount As Integer = 0Static ErrorCount As Integer

You also need to add a decrement to the code path where the user has entered an invalid username.

您还需要向用户输入无效用户名的代码路径添加一个减量。

MessageBox.Show(" Incorrect Username/Password. Login Denied ", " Error! ", MessageBoxButtons.OK, MessageBoxIcon.Error)
ErrorCount = ErrorCount + 1 'add this here

Then move the if so that it is after the SQL so move this to after con.close()

然后将 if 移动到 SQL 之后,将其移动到 after con.close()

If (ErrorCount = 3) Then
    MessageBox.Show(" The System has been Lock ", " Error! ", MessageBoxButtons.OK, MessageBoxIcon.Error)
    Form3.Show()
Else

Also you seem to have some confusion about parameterized queries. If your using parameterized queries then you don't need to concatenate your SQL which should be

此外,您似乎对参数化查询有些困惑。如果您使用参数化查询,那么您不需要连接您的 SQL,它应该是

    str = "SELECT * FROM UserPass WHERE Username=@user AND Password=@pass"

Also the inside if should never be true under normal conditions

在正常情况下,内部 if 永远不应该是真的

If txtPassword.Text <> sdr("Password").ToString Or txtUsername.Text <> sdr("Username").ToString Then 
     ' this code path is only evaluated if the database ignores the where clause or 
     ' the user changes the username or password textboxs whilst the database connection is proccessing and is therfore unnessacary 
     MessageBox.Show(" Incorrect Username/Password. Login Denied ", " Error! ", MessageBoxButtons.OK, MessageBoxIcon.Error)
     ErrorCount = ErrorCount + 1
Else
     MessageBox.Show(" You are now Logged In! ", " Welcome! ", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
     frmOne.Show()
     Me.Hide()
End If

Finally don't store passwords as plaintext. Use a hash from the System.Security.Cryptographynamespacewith a salt.

最后不要将密码存储为明文。使用带有盐的System.Security.Cryptography命名空间中的散列。

回答by Cody Gray

I'm not entirely sure that I understand the question. But this part makes it sound to me like you are trying to lock the computer's entire desktopafter a logon attempt in your programhas failed three times:

我不完全确定我理解这个问题。但这部分对我来说听起来像是在您的程序登录尝试失败三次后试图锁定计算机的整个桌面

What im trying to do is when the user fails to login to the system 3 times, the system will show another form that says the system is locked and the user needs to type in the password from the system to be able to try to log-in again.

我试图做的是当用户登录系统失败 3 次时,系统将显示另一个表单,表示系统已锁定,用户需要从系统输入密码才能尝试登录 -再进去。

I'm not sure that's a good idea. Wouldn't it be sufficient just to lock the user out of your programinstead of locking the entire computer? Think of it like this: there's no reason to inflict a global punishment for a local infraction.

我不确定这是个好主意。仅仅将用户锁定在您的程序之外而不是锁定整个计算机是否就足够了?可以这样想:没有理由对局部违规进行全球惩罚。

But, putting aside whether or not I think it's a good idea, it's perfectly do-able from VB.NET. All you need to do is call the LockWorkStationfunction after your counter indicates that three failed login attempts have occurred. This function is provided as part of the Win32 API, so to call it directly from a .NET application, you'll need to use P/Invoke. This function has a relatively simple signature, so its definition shouldn't be too hard to understand either:

但是,不管我是否认为这是一个好主意,它在 VB.NET 中是完全可行的。您需要做的就是LockWorkStation在您的计数器指示已发生 3 次失败的登录尝试后调用该函数。此函数作为 Win32 API 的一部分提供,因此要直接从 .NET 应用程序调用它,您需要使用 P/Invoke。这个函数有一个比较简单的签名,所以它的定义也不难理解:

<DllImport("user32.dll", SetLastError=True)> _
Public Shared Function LockWorkStation() As Boolean
End Function

This function has some important constraints on its use, namely that it can only be called by processes that are running on the interactive desktop. This is not a problem for you, though, since you're building a GUI application that can only run on the interactive desktop, and you know that if someone has entered an invalid password three times, they're definitely logged in and sitting a few feet from the keyboard.

这个函数在使用上有一些重要的限制,即它只能被运行在交互式桌面上的进程调用。不过,这对您来说不是问题,因为您正在构建一个只能在交互式桌面上运行的 GUI 应用程序,并且您知道如果有人输入了 3 次无效密码,他们肯定已经登录并坐在离键盘几英尺。

Invoking the magic from your code is relatively simple, although it's possible for the function to fail and you should handle those error conditions (lest someone find a security backdoor into your application):

从您的代码中调用魔法相对简单,尽管函数可能会失败,您应该处理这些错误情况(以免有人在您的应用程序中找到安全后门):

If (FailedLogonAttempts < 3) Then
    ' Do whatever...
Else
    ' Lock 'em out!
    Dim success As Boolean = LockWorkstation()
    If Not success Then
        ' Uh-oh! An error occurred! You need to handle this, otherwise someone
        ' might be able to gain unauthorized access to the system.
        '
        ' For demonstration and debugging purposes, we'll throw an exception,
        ' but that's obviously not a secure long-term solution.
        Throw New Win32Exception(Marshal.GetLastWin32Error())
    End If
End If


If you're just asking how to fix your existing code, the problem is that your ErrorCodevariable never goes beyond 0. You've declared it at the top of the btnLogin_Clickmethod like so:

如果您只是询问如何修复现有代码,问题在于您的ErrorCode变量永远不会超过 0。您已在btnLogin_Click方法顶部声明它,如下所示:

Dim ErrorCount As Integer = 0

That's as a regular variable with method-level scope. That means it is re-initialized (to 0, like you ask it to be) every time that the method runs and does not retain its value.

这是具有方法级作用域的常规变量。这意味着每次方法运行时它都会被重新初始化(到 0,就像你要求的那样)并且不保留它的值。

If you want to declare a variable with method-level scope that doesretain its value, you need to declare the variable using the Statickeyword, like so:

如果要声明具有保留其值的方法级作用域的变量,需要使用Static关键字声明该变量,如下所示:

Static ErrorCount As Integer = 0

A great way to test these things, and figure out what's wrong, is to set a breakpoint inside of the btnLogin_Checkmethod and see exactly what values the variables have! If you did that, you'd notice that each time, ErrorCountis set to 0 after execution passes over the first line. That would be your immediate clue as to what the problem is. Then you just have to figure out how to make the value stick. Now you know you do it using the Statickeyword (or moving up a scope, like making it a member of your Form class so that it lives as long as objects of that class).

测试这些事情并找出问题所在的一个好btnLogin_Check方法是在方法内部设置一个断点并准确查看变量具有哪些值!如果你这样做了,你会注意到每次ErrorCount执行通过第一行后,都被设置为 0。这将是您关于问题所在的直接线索。然后你只需要弄清楚如何使价值保持不变。现在您知道您使用Static关键字(或向上移动一个范围,例如使其成为您的 Form 类的成员,以便它与该类的对象一样长)来执行此操作。

回答by Hasan Soherwardi

Imports System.Data.OleDb

Public Class Form1 Private attempt As Integer = 3

公共类 Form1 私人尝试作为整数 = 3

Private Sub cmdLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdLogin.Click
    Dim cn As New OleDbConnection("Provider=Microsoft.Ace.Oledb.12.0; Data Source=" & My.Application.Info.DirectoryPath.ToString() & "\BackUp\testing.Accdb;")
    cn.Open()
    If txtpassword.Text = "" Then
        MsgBox("Please Enter Your Password !!!", MsgBoxStyle.Critical, "Attention...")
        Exit Sub
    End If

    Dim dr1 As OleDbDataReader
    Dim com1 As New OleDbCommand

    com1.CommandText = "select [UserID],[Pass] from userinfo where userid = '" & txtUserID.Text & "'"
    com1.Connection = cn
    If cn.State = ConnectionState.Closed Then cn.Open()
    dr1 = com1.ExecuteReader
    If dr1.Read Then
        If UCase(dr1("Pass")) = UCase(txtpassword.Text) Then
            MessageBox.Show("Welecome")
            Me.Close()
        Else
            MessageBox.Show("Wrong Password  [" & attempt - 1 & "]  Attempt(s) Remaing")
            attempt -= 1
            txtpassword.Focus()
            If attempt = 0 Then
                End
            End If
        End If
        Exit Sub

    Else
        MessageBox.Show("Wrong UserID  [" & attempt - 1 & "]  Attempt(s) Remaing")
        attempt -= 1
        txtpassword.Focus()
        If attempt = 0 Then
            End
        End If
    End If
    cn.Close()
End Sub

Private Sub cmdCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdCancel.Click
    End
End Sub

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    Me.Dispose()
End Sub

End Class

结束班

回答by BizApps

You can try something like this:

你可以尝试这样的事情:

Dim ErrorCount As Int = 0

If (ErrorCount =3) Then
     MessageBox.Show(" The System has been Lock ", " Error! ", MessageBoxButtons.OK, MessageBoxIcon.Error)

'Do stuff 
'Add Your Code to show new Form something like
 Me.Hide()
 Form3.Show()


Else 

Dim con As OleDbConnection = New OleDbConnection( _
           "Provider=Microsoft.Jet.OLEDB.4.0;Data Source= UserPass.mdb;")


con.Open()
Dim str As String
str = "SELECT * FROM UserPass WHERE Username='" & txtUsername.Text & "' AND Password='" & txtPassword.Text & "'"
Dim cmd As OleDbCommand = New OleDbCommand(str, con)
cmd.Parameters.AddWithValue("user", txtUsername.Text)
cmd.Parameters.AddWithValue("pass", txtPassword.Text)
Dim sdr As OleDbDataReader = cmd.ExecuteReader()
' It will be case sensitive if you compare usernames here.   
If sdr.HasRows Then
    If sdr.Read Then
        If txtPassword.Text <> sdr("Password").ToString Or txtUsername.Text <> sdr("Username").ToString Then
            MessageBox.Show(" Incorrect Username/Password. Login Denied ", " Error! ", MessageBoxButtons.OK, MessageBoxIcon.Error)

             ErrorCount = ErrorCount + 1 

        Else
            MessageBox.Show(" You are now Logged In! ", " Welcome! ", MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
            frmOne.Show()
            Me.Hide()
        End If
    End If
Else
    MessageBox.Show(" Incorrect Username/Password. Login Denied ", " Error! ", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If

    sdr.Close()
    con.Close()

End If

Best Regards

此致