2016-05-08 38 views
0

我試圖創建一個使用存儲過程來檢查用戶是否存在和訪問使用VS2015 & SQL Server 2012的使用存儲過程的安全登錄vb.net贏形成

系統vb.net一個登錄表單我有以下表中創建

CREATE TABLE dbo.[User] 
(
    UserID INT IDENTITY(1,1) NOT NULL, 
    LoginName NVARCHAR(40) NOT NULL, 
    PasswordHash BINARY(64) NOT NULL, 
    FirstName NVARCHAR(40) NULL, 
    LastName NVARCHAR(40) NULL, 
    CONSTRAINT [PK_User_UserID] PRIMARY KEY CLUSTERED (UserID ASC) 
) 

並運行以下更新表

ALTER TABLE dbo.[User] ADD Salt UNIQUEIDENTIFIER 
GO 

ALTER PROCEDURE dbo.uspAddUser 
    @pLogin NVARCHAR(50), 
    @pPassword NVARCHAR(50), 
    @pFirstName NVARCHAR(40) = NULL, 
    @pLastName NVARCHAR(40) = NULL, 
    @responseMessage NVARCHAR(250) OUTPUT 
AS 
BEGIN 
    SET NOCOUNT ON 

    DECLARE @salt UNIQUEIDENTIFIER=NEWID() 
    BEGIN TRY 

     INSERT INTO dbo.[User] (LoginName, PasswordHash, Salt, FirstName, LastName) 
     VALUES(@pLogin, HASHBYTES('SHA2_512', @pPassword+CAST(@salt AS NVARCHAR(36))), @salt, @pFirstName, @pLastName) 

     SET @responseMessage='Success' 

    END TRY 
    BEGIN CATCH 
     SET @responseMessage=ERROR_MESSAGE() 
    END CATCH 

END 

從這個來源所有基於

我創建了一個簡單的形式與用戶名和密碼框提交按鈕,我使用下面的代碼提交按鈕

Private Sub RadButtonSubmit_Click(sender As Object, e As EventArgs) Handles RadButtonSubmit.Click 
     Dim dt As New DataTable() 
     Dim adp As New SqlDataAdapter() 
     Try 
      Dim con As New SqlConnection(My.Settings.Connection) 
      Dim cmd As New SqlCommand("uspLogin", con) 
      cmd.CommandType = CommandType.StoredProcedure 
      cmd.Parameters.AddWithValue("@pLoginName", RadTextBoxUser.Text.Trim()) 
      cmd.Parameters.AddWithValue("@pPassword", RadTextBoxPass.Text.Trim()) 
      adp.SelectCommand = cmd 
      adp.Fill(dt) 
      cmd.Dispose() 
      If dt.Rows.Count > 0 Then 
       RadLabelMessage.Text = "Login Successfull" 
       'Or in show messagebox using ScriptManager.RegisterStartupScript(this, this.GetType(), "Message", "alert('Login Successfull');", true); 
       'Or write using Response.Write("Login Successfull"); 
       'Or redirect using Response.Redirect("Mypanel.aspx"); 
      Else 
       RadLabelMessage.Text = "Wrong Username/Password" 
       'Or show in messagebox usingScriptManager.RegisterStartupScript(this, this.GetType(), "Message", "alert('Wrong Username/Password');", true); 
       'Or write using Response.Write("Wrong Username/Password"); 
      End If 
     Catch ex As Exception 
      'RegisterStartupScript(Me, Me.[GetType](), "Message", "alert('Oops!! following error occured : " & ex.Message.ToString() & "');", True) 
      ' Response.Write("Oops!! following error occured: " +ex.Message.ToString());   
     Finally 
      dt.Clear() 
      dt.Dispose() 
      adp.Dispose() 
     End Try 
    End Sub 

當我輸入用戶名和密碼,它總是顯示「錯誤的用戶名/密碼」

我添加使用用戶

DECLARE @responseMessage NVARCHAR(250) 

EXEC dbo.uspAddUser 
      @pLogin = N'Admin', 
      @pPassword = N'123', 
      @pFirstName = N'Admin', 
      @pLastName = N'Administrator', 
      @[email protected] OUTPUT 

SELECT * 
FROM [dbo].[User] 

這是登錄存儲過程

CREATE PROCEDURE dbo.uspLogin 
    @pLoginName NVARCHAR(254), 
    @pPassword NVARCHAR(50), 
    @responseMessage NVARCHAR(250)='' OUTPUT 
AS 
BEGIN 

    SET NOCOUNT ON 

    DECLARE @userID INT 

    IF EXISTS (SELECT TOP 1 UserID FROM [dbo].[User] WHERE [email protected]) 
    BEGIN 
     SET @userID=(SELECT UserID FROM [dbo].[User] WHERE [email protected] AND PasswordHash=HASHBYTES('SHA2_512', @pPassword+CAST(Salt AS NVARCHAR(36)))) 

     IF(@userID IS NULL) 
      SET @responseMessage='Incorrect password' 
     ELSE 
      SET @responseMessage='User successfully logged in' 
    END 
    ELSE 
     SET @responseMessage='Invalid login' 

END 

我可以看到用戶存在於我的分貝我如何能解決這個問題

感謝 M之外的任何建議

我用下面的代碼

Imports System.Net.Sockets 
Imports System 
Imports System.IO 
Imports System.Security.Cryptography 
Imports System.Text.RegularExpressions 
Imports System.Data.SqlClient 


Public Class Login 
    Private FirstNameValid As Boolean 'Is Name Valid? 
    Private LastNameValid As Boolean 'Is Surname Valid? 
    Private XUserNameValid As Boolean 
    Private UserPassValid As Boolean 
    Private EmailValid As Boolean 'Is Email Valid? 

    Private Sub FirstName_Leave(sender As Object, e As System.EventArgs) Handles FirstName.Leave 
     If FirstName.Text = "" Then ErrorLabel.Text = "Please Enter Your First Name!" 
     'If Not A Matching Format Entered 
     If Not Regex.Match(FirstName.Text, "^[a-z]*$", RegexOptions.IgnoreCase).Success Then 'Only Letters 

      ErrorLabel.Text = "Please Enter Alphabetic Characters Only!" 'Inform User 

      FirstName.Focus() 'Return Focus 
      FirstName.Clear() 'Clear TextBox 

      FirstNameValid = False 'Boolean = False 
     Else 

      FirstNameValid = True 'Everything Fine 
      ErrorLabel.Text = "" 
     End If 

    End Sub 

    Private Sub LastName_Leave(sender As Object, e As System.EventArgs) Handles LastName.Leave 

     'Create A Pattern For Surname 
     Dim strSurname As String = "^[a-zA-Z\s]+$" 

     Dim reSurname As New Regex(strSurname) 'Attach Pattern To Surname Textbox 

     'Not A Match 
     If Not reSurname.IsMatch(LastName.Text) Then 

      ErrorLabel.Text = "Please Enter Alphabetic Characters Only!" 

      LastName.Focus() 

      LastName.Clear() 

      LastNameValid = False 

     Else 

      LastNameValid = True 
      ErrorLabel.Text = "" 

     End If 

    End Sub 
    Private Sub UserPass_Leave(sender As Object, e As System.EventArgs) Handles UserPass.Leave 
     If UserPass.Text = "" Then ErrorLabel.Text = "Please Enter Your Password!" 
     If UserPass.Text.Length < "8" Then 

      ErrorLabel.Text = "Password must be 8 Charecters!" 
      UserPass.Focus() 

      UserPass.Clear() 

      UserPassValid = False 

     Else 

      UserPassValid = True 
      ErrorLabel.Text = "" 

     End If 

    End Sub 

    Private Sub ValidateEmail() 

     'Set Up Reg Exp Pattern To Allow Most Characters, And No Special Characters 
     Dim reEmail As Regex = New Regex("([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\." + 
     ")|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})", 
     RegexOptions.IgnoreCase _ 
     Or RegexOptions.CultureInvariant _ 
     Or RegexOptions.IgnorePatternWhitespace _ 
     Or RegexOptions.Compiled 
     ) 

     Dim blnPossibleMatch As Boolean = reEmail.IsMatch(UserEmail.Text) 

     If blnPossibleMatch Then 

      'Check If Entered Email Is In Correct Format 
      If Not UserEmail.Text.Equals(reEmail.Match(UserEmail.Text).ToString) Then 

       ErrorLabel.Text = "Invalid Email Address!" 

      Else 

       EmailValid = True 'Email is Perfect 

      End If 

     Else 'Not A Match To Pattern 

      EmailValid = False 'Set Boolean Variable To False 

      ErrorLabel.Text = "Invalid Email Address!" 'Inform User 

      UserEmail.Clear() 'Clear Textbox 

      UserEmail.Focus() 'Set Focus To TextBox 

     End If 

    End Sub 

    Private Sub txtEmail_LostFocus(sender As Object, e As System.EventArgs) Handles UserEmail.LostFocus 
     If UserEmail.Text = "" Then ErrorLabel.Text = "Invalid Email Address!" 
     ValidateEmail() 'Check Email Validity 

    End Sub 
    'The maximum number of times the user can try to login. 
    Private Const MAX_ATTEMPT_COUNT As Integer = 3 

    'The number of times the user has tried to login. 
    Private attemptCount As Integer = 0 


    Private Sub Login_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
     RadPanel1.Show() 
     RadPanel2.Hide() 
     RadLabel7.Text = "Register" 

     TextBoxUserName.Focus() 
     Dim splash As SplashScreen1 = CType(My.Application.SplashScreen, SplashScreen1) 
     Dim MadeUpSteps() As String = {"Initializing...", "Loading ports...", "Checking Connection...", "Please wait...", "Connecting..."} 

     For i As Integer = 0 To MadeUpSteps.Length - 1 
      splash.UpdateProgress(MadeUpSteps(i), CInt((i + 1)/MadeUpSteps.Length * 100)) 
      System.Threading.Thread.Sleep(1500) 
     Next 
     Dim tcpc As New TcpClient() 
     Try 
      tcpc.Connect("cloud01.smarthosting.co.uk", 80) 
      Return 
     Catch 


      If MessageBox.Show("Sorry No connection is available try again later.", 
        "Connection Error", 
        MessageBoxButtons.OK, 
        MessageBoxIcon.Error) = Windows.Forms.DialogResult.OK Then 

       Me.DialogResult = Windows.Forms.DialogResult.Cancel 
       Me.Close() 

      End If 

     End Try 
    End Sub 
    Dim adminLogin As Boolean 


    Private Sub OK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK.Click 


     Dim x As New System.Security.Cryptography.SHA512CryptoServiceProvider() 
     Dim bs As Byte() = System.Text.Encoding.UTF8.GetBytes(TextBoxPassword.Text) 
     bs = x.ComputeHash(bs) 
     Dim s As New System.Text.StringBuilder() 
     For Each b As Byte In bs 
      s.Append(b.ToString("x2").ToLower()) 
     Next 
     TextBoxPassword.Text = s.ToString() 
     Dim pass = TextBoxPassword.Text 

     If Me.ValidateCredentials Then 
      Dim Obj As New Main 
      adminLogin = False 
      My.Forms.Main.RadTextBox1.Text = adminLogin 
      Me.DialogResult = Windows.Forms.DialogResult.OK 



     ElseIf Me.ValidateCredentials1 Then 
      Dim Obj As New Main 
      adminLogin = True 
      My.Forms.Main.RadTextBox1.Text = adminLogin 
      Me.DialogResult = Windows.Forms.DialogResult.OK 


     Else 
      Me.attemptCount += 1 

      Dim message As String 

      If Me.attemptCount = MAX_ATTEMPT_COUNT Then 
       message = "The maximum number of failed logins has been reached." & 
          Environment.NewLine & 
          "The application will now exit." 
       Me.DialogResult = Windows.Forms.DialogResult.Abort 
      Else 
       message = "The provided credentials are incorrect." & 
          Environment.NewLine & 
          "Please try again." 
       Me.TextBoxPassword.Clear() 
       Me.TextBoxUserName.SelectAll() 
       Me.TextBoxUserName.Select() 
      End If 

      MessageBox.Show(message, 
          "Login Failed", 
          MessageBoxButtons.OK, 
          MessageBoxIcon.Error) 
     End If 

    End Sub 

    Private Sub Cancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel.Click 
     If MessageBox.Show("Are you sure you want to exit without logging in?", 
          "Confirm Exit", 
          MessageBoxButtons.YesNo, 
          MessageBoxIcon.None) = Windows.Forms.DialogResult.Yes Then 
      Me.DialogResult = Windows.Forms.DialogResult.Cancel 
     End If 
    End Sub 

    Private Function ValidateCredentials() As Boolean 
     Dim result As Boolean 


     result = Me.ValidateCredentialsByTableAdapter() 

     Return result 
    End Function 

    Private Function ValidateCredentialsByTableAdapter() As Boolean 
     Using adapter As New System3DataSetTableAdapters.UserTableAdapter 
      Return adapter.ScalarQuery(Me.TextBoxUserName.Text.Trim(), 
                  Me.TextBoxPassword.Text).Value > 0 
     End Using 
    End Function 
    Private Function ValidateCredentials1() As Boolean 
     Dim result As Boolean 


     result = Me.ValidateCredentialsByTableAdapter1() 

     Return result 
    End Function 

    Private Function ValidateCredentialsByTableAdapter1() As Boolean 
     Using adapter As New System3DataSetTableAdapters.Admin8TableAdapter 
      Return adapter.ScalarQuery(Me.TextBoxUserName.Text.Trim(), 
                  Me.TextBoxPassword.Text).Value > 0 
     End Using 
    End Function 

    Private Sub RadLabel7_Click(sender As Object, e As EventArgs) Handles RadLabel7.Click 
     If RadPanel1.Visible = True Then 
      RadLabel7.Text = "Login" 
      RadPanel2.Show() 
      RadPanel1.Hide() 


     ElseIf RadPanel2.Visible = True Then 
      RadLabel7.Text = "Register" 
      RadPanel1.Show() 
      RadPanel2.Hide() 

     End If 

    End Sub 

    Private Sub RadButton1_Click(sender As Object, e As EventArgs) Handles RadButton1.Click 
     Dim x As New System.Security.Cryptography.SHA512CryptoServiceProvider() 
     Dim bs As Byte() = System.Text.Encoding.UTF8.GetBytes(UserPass.Text) 
     bs = x.ComputeHash(bs) 
     Dim s As New System.Text.StringBuilder() 
     For Each b As Byte In bs 
      s.Append(b.ToString("x2").ToLower()) 
     Next 
     UserPass.Text = s.ToString() 
     Dim pass = UserPass.Text 
     Dim myConnection As New System.Data.ConnectionState 
     Dim mySqlDataAdapter As New SqlDataAdapter("Select * from Users", myConnection) 
     Dim myDataSet As New DataSet() 
     Dim myDataRow As DataRow 

     ' Create command builder. This line automatically generates the update commands for you, so you don't 
     ' have to provide or create your own. 
     Dim mySqlCommandBuilder As New SqlCommandBuilder(mySqlDataAdapter) 

     ' Set the MissingSchemaAction property to AddWithKey because Fill will not cause primary 
     ' key & unique key information to be retrieved unless AddWithKey is specified. 
     mySqlDataAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey 

     mySqlDataAdapter.Fill(myDataSet, "Users") 

     myDataRow = myDataSet.Tables("Users").NewRow() 
     myDataRow("ID") = "NewID" 
     myDataRow("xFirstName") = FirstName.Text 
     myDataRow("xLastName") = LastName.Text 
     myDataRow("xEmail") = UserEmail.Text 
     myDataRow("UserPass") = pass 

     myDataSet.Tables("Users").Rows.Add(myDataRow) 
    End Sub 
End Class 
Public Class PasswordHash 

    Public Const SALT_BYTE_SIZE As Integer = 24 
    Public Const HASH_BYTE_SIZE As Integer = 24 
    Public Const PBKDF2_ITERATIONS As Integer = 1000 

    Public Const ITERATION_INDEX As Integer = 0 
    Public Const SALT_INDEX As Integer = 1 
    Public Const PBKDF2_INDEX As Integer = 2 


    Public Shared Function CreateHash(password As String) As String 
     ' Generate a random salt 
     Dim csprng As New RNGCryptoServiceProvider() 
     Dim salt As Byte() = New Byte(SALT_BYTE_SIZE - 1) {} 
     csprng.GetBytes(salt) 

     ' Hash the password and encode the parameters 
     Dim hash As Byte() = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE) 
     Return PBKDF2_ITERATIONS + ":" + Convert.ToBase64String(salt) + ":" + Convert.ToBase64String(hash) 
    End Function 

    ''' <summary> 
    ''' Validates a password given a hash of the correct one. 
    ''' </summary> 
    ''' <param name="password">The password to check.</param> 
    ''' <param name="correctHash">A hash of the correct password.</param> 
    ''' <returns>True if the password is correct. False otherwise.</returns> 
    Public Shared Function ValidatePassword(password As String, correctHash As String) As Boolean 
     ' Extract the parameters from the hash 
     Dim delimiter As Char() = {":"c} 
     Dim split As String() = correctHash.Split(delimiter) 
     Dim iterations As Integer = Int32.Parse(split(ITERATION_INDEX)) 
     Dim salt As Byte() = Convert.FromBase64String(split(SALT_INDEX)) 
     Dim hash As Byte() = Convert.FromBase64String(split(PBKDF2_INDEX)) 

     Dim testHash As Byte() = PBKDF2(password, salt, iterations, hash.Length) 
     Return SlowEquals(hash, testHash) 
    End Function 

    ''' <summary> 
    ''' Compares two byte arrays in length-constant time. This comparison 
    ''' method is used so that password hashes cannot be extracted from 
    ''' on-line systems using a timing attack and then attacked off-line. 
    ''' </summary> 
    ''' <param name="a">The first byte array.</param> 
    ''' <param name="b">The second byte array.</param> 
    ''' <returns>True if both byte arrays are equal. False otherwise.</returns> 
    Private Shared Function SlowEquals(a As Byte(), b As Byte()) As Boolean 
     Dim diff As UInteger = CUInt(a.Length) Xor CUInt(b.Length) 
     Dim i As Integer = 0 
     While i < a.Length AndAlso i < b.Length 
      diff = diff Or CUInt(a(i) Xor b(i)) 
      i += 1 
     End While 
     Return diff = 0 
    End Function 

    ''' <summary> 
    ''' Computes the PBKDF2-SHA1 hash of a password. 
    ''' </summary> 
    ''' <param name="password">The password to hash.</param> 
    ''' <param name="salt">The salt.</param> 
    ''' <param name="iterations">The PBKDF2 iteration count.</param> 
    ''' <param name="outputBytes">The length of the hash to generate, in bytes.</param> 
    ''' <returns>A hash of the password.</returns> 
    Private Shared Function PBKDF2(password As String, salt As Byte(), iterations As Integer, outputBytes As Integer) As Byte() 
     Dim pbkdf2__1 As New Rfc2898DeriveBytes(password, salt) 
     pbkdf2__1.IterationCount = iterations 
     Return pbkdf2__1.GetBytes(outputBytes) 
    End Function 
End Class 
+0

我想你應該修改你的問題以添加SQL源代碼,您uspLogin存儲過程,即使是相同的,你所提供的鏈接(我們不知道這是)。 –

回答

0

重新登錄表單uspLogin存儲過程將其結果作爲@responseMessage輸出參數返回,而不是結果集。所以你的用於登錄的.NET代碼不應該使用DataTable來獲得結果;相反,它應該定義一個@responseMessage輸出參數。

使用這樣的代碼:

Dim resultParam = cmd.Parameters.Add("@responseMessage", SqlDbType.NVarChar, 250) 
resultParam.Direction = ParameterDirection.Output 
cmd.ExecuteNonQuery() 
Dim res = resultParam.Value.ToString()