我是编程新手,并尝试通过youtube教程学习VB.net。
我创建了一个Windows窗体应用,供用户创建新帐户。
为了安全起见,我还尝试应用hash和salt技术来存储密码。
我遇到的主要问题是维护一个名为“DatabaseManager”和“DataHandling”的两个类,“btnRegister”中的代码和名为“Test”的数据库之间的成功连接。
程序运行正常。当我在填写“txtUsername.Text”和“txtPassword.Text”后单击btnRegister时,它会显示错误"Column
User_ID does not allow nulls."
。
所以这就是我不断遇到问题的地方。我试图让它工作很多,我不知道它为什么不记录新数据。这是我的代码。我使用V Studio 2012.请帮忙。 为了清楚起见,我复制了一些来自互联网的代码并试图让它们与班级一起工作
Imports System
Imports System.IO
Imports System.Text
Imports System.Data.OleDb
Imports System.Data
Imports System.Windows.Forms
Imports System.Data.SqlClient
Imports System.Security.Cryptography
Public Class DatabaseManager
Private Const CONNECTION_STRING As String = "Data Source=(localdb)\Projects;Initial Catalog=Test;Integrated Security=True"
Private connection As SqlConnection = Nothing
Private usersdataadapter As SqlDataAdapter = Nothing
Sub New()
connection = New SqlConnection(CONNECTION_STRING)
usersdataadapter = New SqlDataAdapter("select * from Test", connection)
End Sub
Public Sub Register(ByVal Username As String, ByVal Password As String)
connection.Open()
Dim usersDataset As New DataSet()
usersdataadapter.FillSchema(usersDataset, SchemaType.Source, "Test")
Dim table As DataTable = usersDataset.Tables("Test")
Dim newRecord As DataRow = table.NewRow()
newRecord("Username") = Username
newRecord("Password") = Password
table.Rows.Add(newRecord)
Dim command As New SqlCommandBuilder(usersdataadapter)
usersdataadapter.Update(usersDataset, "Test")
usersDataset.Dispose()
connection.Close()
End Sub
Public Function UsernameAvailable(ByVal username As String) As Boolean
Dim usersDataset As New DataSet()
usersdataadapter.FillSchema(usersDataset, SchemaType.Source, "Test")
usersdataadapter.Fill(usersDataset, "Test")
Dim table As DataTable = usersDataset.Tables("Test")
For i As Integer = 0 To table.Rows.Count - 1
Dim currnetUser As String = table.Rows(i)("Username").ToString().Trim()
If (currnetUser = username) Then
usersDataset.Dispose()
connection.Close()
Return False
End If
Next
Return True
usersDataset.Dispose()
connection.Close()
End Function
Public Function Login(ByVal username As String, ByVal password As String) As Boolean
Dim usersDataset As New DataSet()
usersdataadapter.FillSchema(usersDataset, SchemaType.Source, "Test")
usersdataadapter.Fill(usersDataset, "Test")
Dim table As DataTable = usersDataset.Tables("Test")
For i As Integer = 0 To table.Rows.Count - 1
Dim currnetUser As String = table.Rows(i)("Username").ToString().Trim()
Dim currnetPassword As String = table.Rows(i)("Password").ToString().Trim()
If (currnetUser = username AndAlso currnetPassword = password) Then
usersDataset.Dispose()
connection.Close()
Return True
End If
Next
usersDataset.Dispose()
connection.Close()
Return False
End Function
End Class
Imports System
Imports System.Text
Imports System.Data.OleDb
Imports System.Data
Imports System.Data.SqlClient
Imports System.Windows.Forms
Imports System.Security.Cryptography
Public Class DataHandling
Inherits Form1
Public Shared Function GenerateRandomString() As String
Dim i_key As Integer
Dim Random1 As Single
Dim arrIndex As Int16
Dim sb As New StringBuilder
Dim RandomLetter As String
Dim KeyLetters As String = "abcdefghijklmnopqrstuvwxyz"
Dim KeyNumbers As String = "0123456789"
Dim KeyLength As Integer = 12
Dim LettersArray = KeyLetters.ToCharArray
Dim NumbersArray = KeyNumbers.ToCharArray
For i_key = 1 To KeyLength
Randomize()
Random1 = Rnd()
arrIndex = -1
If (CType(Random1 * 111, Integer)) Mod 2 = 0 Then
Do While arrIndex < 0
arrIndex = _
Convert.ToInt16(LettersArray.GetUpperBound(0) _
* Random1)
Loop
RandomLetter = LettersArray(arrIndex)
If (CType(arrIndex * Random1 * 99, Integer)) Mod 2 <> 0 Then
RandomLetter = LettersArray(arrIndex).ToString
RandomLetter = RandomLetter.ToUpper
End If
sb.Append(RandomLetter)
Else
Do While arrIndex < 0
arrIndex = _
Convert.ToInt16(NumbersArray.GetUpperBound(0) _
* Random1)
Loop
sb.Append(NumbersArray(arrIndex))
End If
Next
Return sb.ToString
End Function
Public Shared Function CheckPassword(ByVal plainText As String, ByVal passwordHash As Byte(), ByVal salt As Byte()) As Boolean
Dim encoding As New System.Text.UTF8Encoding
'Retrieve Salt String from byte array
Dim saltStr As String = encoding.GetString(salt)
Dim hashable As String = Trim(plainText) & Trim(saltStr)
' Convert into hash strings
Dim testhash As String = EncryptStringAsHash(hashable)
Dim realHash As String = encoding.GetString(passwordHash)
' Compare and return result
Return testhash = realHash
End Function
Public Shared Function EncryptStringAsHash(ByVal value As String) As String
Dim encoding As New System.Text.UTF8Encoding
Dim stringBytes As Byte() = encoding.GetBytes(value)
Dim SHhash As SHA512Managed = New SHA512Managed
Dim hash As String = Convert.ToBase64String(SHhash.ComputeHash(stringBytes))
Return hash
End Function
Public Shared Function ConvertStringToByteArray(ByVal value As String) As Byte()
Dim encoding As New System.Text.UTF8Encoding
Return encoding.GetBytes(value)
End Function
End Class
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography
Imports System.Data.OleDb
Imports System.Windows.Forms
Imports System.Data.OleDb.OleDbConnection
Imports System.Data.SqlClient
Public Class Form1
Dim maxrows As Integer
Dim incdec As Integer
Dim con As New OleDb.OleDbConnection
Dim dbprovider As String
Dim dbsource As String
Dim ds As New DataSet
Dim da As OleDb.OleDbDataAdapter
Dim sql As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim con As New OleDbConnection
Dim dbprovider As String
Dim dbsource As String
dbprovider = "PROVIDER = Microsoft.ACE.OLEDB.12.0;"
dbsource = "Data Source=(localdb)\Projects;Initial Catalog=Test;Integrated Security=True"
con.ConnectionString = dbprovider & dbsource
End Sub
Private Sub btnRegister_Click(sender As Object, e As EventArgs) Handles btnRegister.Click
Dim dbmanager As New DatabaseManager
Dim Data As New DataHandling
'Generate Hash and Salt for password
Dim salt As String = DataHandling.GenerateRandomString
Dim hashable As String = Trim(txtPassword.Text) & Trim(salt) 'txtPassword.Text used to be password
Dim hash As String = DataHandling.EncryptStringAsHash(hashable)
Dim confirmationId As String = System.Guid.NewGuid.ToString
Dim reg As user
reg.Username = txtUsername.Text 'txtUsername.Text used to be username
reg.Password = DataHandling.ConvertStringToByteArray(hash)
reg.Salt = DataHandling.ConvertStringToByteArray(salt)
If dbmanager.UsernameAvailable(txtUsername.Text) Then
dbmanager.Register(txtUsername.Text, txtPassword.Text)
Dim password As String
If txtPassword.Text = String.Empty Then
password = "217tABCDEF42#$tolq"
Else
password = txtPassword.Text
End If
Dim salt As String = GenerateRandomString(12)
Dim hashable As String = Trim(password) & Trim(salt)
MsgBox("Hashable = " & hashable)
Dim hash As String = EncryptStringAsHash(hashable)
CheckPassword(password, ConvertStringToByteArray(hash), ConvertStringToByteArray(salt))
frmAccessGranted.Show()
Me.Hide()
Else
MessageBox.Show("Cannot Register, Username Already Taken!")
End If
End Sub
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
txtUsername.Clear()
txtPassword.Clear()
End Sub
End Class
答案 0 :(得分:0)
我认为您的User表User_id值只是缺少Identity Specification选项。它使User_id字段自动生成,并为您添加到
中的每个用户增加1(默认情况下)如果您有SQL Server管理工作室,则可以将此选项放在:
右键点击User table -> Select "Desing" -> Select "User_id" field -> in "Column Propetries"
窗口,将“Indentity Specification
”选项设为“Yes
”并保存
示例SQL创建表的命令可能是这样的:
CREATE TABLE User (User_id BIGINT IDENTITY NOT NULL, Username NVARCHAR(100) NOT NULL, Password NVARCHAR(100) NOT NULL)
答案 1 :(得分:0)
代码中的问题不在VB端,而是在数据库中。
您已将主键设置为UserId,但您没有将任何值传递给userId,您只是将值传递给用户名和密码。
所以有两种方法可以解决这个问题
您可以通过以下代码将UserId列作为自动增量字段
CREATE TABLE [dbo]。[Test1]( [id] [int] IDENTITY(1,1)NOT NULL, YourColumnname1数据类型, YourColumnname2数据类型
)
这仅适用于sqlserver 2008的更高版本
alter table tablename
alter column columnname
add Identity(100,1)
了解更多 Click here