VB.net and Mysql Login Problem Using Two Tables - mysql

How can i login using doctor level in his table.Because everytime i log the receptionist form is always popping even when i log using the user and pass of the doctor maybe my syntax is wrong please help me
PS: Doctors Forms and Receptionists Forms are different.
This is my code:
Try
mycon.Open()
Dim query1 As String
Dim query2 As String
Dim name As String
query1 = "SELECT * FROM receptionisttbl"
command = New MySqlCommand(query1, mycon)
reader = command.ExecuteReader
With reader
.Read()
If .Item("level") = "1" Then
With reader
.Read()
name = .Item("name")
End With
MsgBox("Welcome " + name)
Form1.Show()
command.Dispose()
reader.Close()
mycon.Close()
Else
mycon.Open()
query2 = "SELECT * FROM doctortbl"
command = New MySqlCommand(query2, mycon)
reader = command.ExecuteReader
With reader
.Read()
If .Item("level") = "2" Then
With reader
.Read()
name = .Item("name")
End With
MsgBox("Welcome " + name)
Form2.Show()
command.Dispose()
reader.Close()
mycon.Close()
End If
End With
End If
End With
Catch ex As Exception
MsgBox(ex.ToString)
Finally
mycon.Dispose()
End Try

First, let's consider your requirements.
Provide a login form to validate users.
If the user is valid (userName and matching password are found in the database) then display a Form based on the level of the user.
Considering the requirements look at the design of the table in the database. Let's call it MDUsers.
Now to the columns.
UserName as an VarChar size 100 and Primary key of the table
UserPassword as VarChar size 100
Level an Integer
Now you have fields for all the data you need for your requirements.
Add some sample data to your table.
Next think about what you need from the user to accomplish your requirements. Design your user interface accordingly.
Your login form will have 2 text boxes (userName and password) and a button (Login).
Then you need to think about the code for the Login button.
You need to connect to your database and check if there is a match to userName and password. Once you find a match you only need to retrieve a single piece of data to complete your requirements, the level.
Now how can we ask the database to do all that?
Select level From MDUsers Where userName = #userName And UserPassword = #pword;
Since userName is the Primary Key of the table we know we will find no more than one record with that userName. If the password matches too then we have a valid user and we will return the single piece of data, level for that record.
Using...End Using blocks ensure that your database objects are closed and disposed even if there is an error. You can pass your connection string directly to the constructor of the connection and pass the query string and connection to the constructor of the command.
Always use parameters.
Since we only need a single piece of data we can use .ExecuteScalar
Private Sub OpCode()
Dim retVal As Object
Using cn As New MySqlConnection("Your connection string"),
cmd As New MySqlCommand("Select level From MDUsers Where userName = #userName And UserPassword = #pword;", cn)
cmd.Parameters.Add("#userName", MySqlDbType.VarChar, 100).Value = txtName.Text
cmd.Parameters.Add("#pword", MySqlDbType.VarChar, 100).Value = txtPassword.Text
cn.Open()
retVal = cmd.ExecuteScalar
End Using
If retVal Is Nothing Then
MessageBox.Show("Login failed")
Return
End If
If CInt(retVal) = 1 Then
Form1.Show()
ElseIf CInt(retVal) = 2 Then
Form2.Show()
Else
MessageBox.Show("Level not recognized")
End If
End Sub
You will have to check MySql rules for column names and table names being aware of reserved words.

Related

BCrypt generate hash and salt then compare to MySQL database

I'm looking to BCrypt to hash and salt and compare it to the hash stored in my database. There seems to be a lack of vb.net with BCrypt, which is why I'm asking.
So, from what I understand is we generate a hash and a salt when the user enters their password. Then we compare that hash to the one in the database, however since I've found nothing online for vb.net I'm not sure how to do it.
This is what I have so far. If the code looks messy it's because I copied and pasted it from Visual Studio to here, on VS it looks neat and tidy.
Now I know there will be flaws with the code etc. I'm not that bothered as this is for personal use and learning. Just need to learn how to generate salt + hash with BCrypt and then compare it with the already hash & salted password in my database but in terms of how to go about and redo this bit of code and implement the check that both salt & hashes are the same I'm stuck.
Dim pw As String = TextBox_Password.Text
Dim Salt As String = BCrypt.Net.BCrypt.GenerateSalt(12)
Dim Hash As String = BCryot.Net.BCrypt.HashPassword(pw, salt)
Try
Connection.Open()
Dim SQLQuery
SQLQuery = "SELECT * FROM `core_members` where name='" & TextBox_Username & " ' and members_pass_hash='" & I don't know if you're meant to put Hash? here to hash the inputed password from the user? Or the TextBox_Password.Text & "'"
'As for the verify function... to compare the hashed password I do try to do this
If (BCRYpt.Net.BCrypt.Verify(pw, hash)) Then
Command1 = New MySqlCommand(SQLQuery, Connection)
READER = Command1.ExecuteReader
Dim Count As Integer
count = 0
While READER.read
count += 1
end while
READER.close()
If count = 1 then
'User Successfully Logged In
end if
'I definitely know the count = 1 etc probably not the best way to allow a user to login. I've seen something with MyData.HasRows or something like that to login?
'I know that the code above is probably no where near close to actually how it's done but as I said due to the lack of documentation with vb.net and BCrypt not making it easy.
Any help with cleaning up the login function would be great including comparing the hashed password in my database.
Just want to give the biggest thanks to #Mary for being so kind and helpful for providing a solution to solve my biggest problem thus far! Thank you!
I'm only making this Answer because for me there were a few typo's I had to fix, but all of it goes to Mary!
So, first off I'm using a mysql.dat.dll which uses Imports MySql.Data.MySqlClient (Which changes a few things from Mary's code)
Imports Crypt = BCRypt.Net.BCrypt - Allows us to use Crypt Instead of having to type the whole BCrypt.Net.BCrypt
Please note for me, if your textbox's are empty then you will get an error Object Reference not set to an instance of an object. This is if you're on visual studio. It won't happen if you run the program as a normal user. I will tell the user make sure they have entered a username and password
Imports Crypt = BCRypt.Net.BCrypt
Private Sub VerifyPassword()
try
Dim Password As String = "TextBox_UserPassword"
Dim Hashword As String = ""
Using Conn As New MySqlCommand(Connection),
Command As New MySqlCommand("SELECT password FROM members where Username= #Username;", Conn)
Command.Parameters.Add("#Username", MySqlDbType.VarChar).Value = TextBox_Username
Conn.Open()
Hashword = Command.ExecuteScalar.ToString
End Using
Dim Result = Crypt.Verify(Password, Hashword)
If result = true then
MsgBox("Logged in")
else
MsgBox("Logged in Failed")
end if
Catch ex As Exception
MessageBox.Show(ex.Message) 'Optional'
MsgBox("Make sure have entered a Username or Password", vbcritical) 'If the textbox have nothing it will remind the user to make sure they enter a username or password'
End try
End Sub
I used Sql Server to test code because it was what I had handy. It will work the same for MySql. With BCrypt you don't have to store the salt separately.
Private Sub InsertNewUser()
Dim HashWord As String = BCrypt.Net.BCrypt.HashPassword(TextBox2.Text, BCrypt.Net.BCrypt.GenerateSalt(12))
Using cn As New SqlConnection(My.Settings.PublishCon),
cmd As New SqlCommand("Insert Into Users (UserName, Password) Values (#Name, #HashWord);", cn)
cmd.Parameters.Add("#Name", SqlDbType.VarChar, 100).Value = TextBox1.Text
cmd.Parameters.Add("#HashWord", SqlDbType.VarChar, 100).Value = HashWord
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub
Private Sub VerifyPassword()
Dim pw As String = TextBox2.Text
Dim HashWord As String = ""
Using cn As New SqlConnection(My.Settings.PublishCon),
cmd As New SqlCommand("SELECT Password FROM Users where UserName= #UserName;", cn)
cmd.Parameters.Add("#UserName", SqlDbType.VarChar).Value = TextBox1.Text
cn.Open()
HashWord = cmd.ExecuteScalar.ToString
End Using
Dim result = BCrypt.Net.BCrypt.Verify(pw, HashWord)
If result Then
MessageBox.Show("Successful Login")
Else
MessageBox.Show("Sorry login failed")
End If
End Sub

Parameterize SQL Queries

I want parameterize some SQL Statements so my code isn't vunerable to SQL Injections any longer But i have actually no plan how to parameterize for example a where clause.
Dim accID As String = DatabaseConnecter.readField("SELECT ID FROM accounts WHERE accountname ='" & user & "' AND password='" & pw & "';")
The Problem is if you type in a given username, for example test and extend the username with. You can log in without entering the password into the Application.
Edit:
Public Function readField(ByVal sql As String) As String
Dim output As String = "ERROR"
Using cn = New MySqlConnection(connString.ToString())
Using cmd = New MySqlCommand(sql, cn)
cn.Open()
Using rd = cmd.ExecuteReader()
Try
rd.Read()
output = rd.GetString(0)
rd.Close()
Catch ex As Exception
End Try
End Using
cn.Close()
End Using
End Using
Return output
End Function
ยดยดยด
To have a parameterized query you need to create parameters and write a proper SQL text where, in place of values typed directly from your user, you have parameter placeholders.
So, for example, you sql text should be something like this
Dim sqlText = "SELECT ID FROM accounts WHERE accountname =#name AND password=#pwd"
Now you have a parameterized text, but stil we need to create the parameters that will be sent to the database engine together with your sql command.
You can create the parameter (two in this case) in this way before calling the method that executes the query
Dim p1 as MySqlParameter = new MySqlParameter("#name", MySqlDbType.VarChar)
p1.Value = user
Dim p2 as MySqlParameter = new MySqlParameter("#pwd", MySqlDbType.VarChar)
p2.Value = password
Dim pms As List(Of MySqlParameter) = new List(Of MySqlParameter)()
pms.Add(p1)
pms.Add(p2)
Now we need to pass this list to your method (and this requires changes to your method signature)
DatabaseConnecter.readField(sqlText, pms)
The method itself should change to something like
Public Function readField(ByVal sql As String, Optional pms As List(Of MySqlParameter) = Nothing) As String
Dim output As String = "ERROR"
Using cn = New MySqlConnection(connString.ToString())
Using cmd = New MySqlCommand(sql, cn)
cn.Open()
' This block adds the parameter defined by the caller to the command
' The parameters are optional so we need to check if we have really received the list or not
if pms IsNot Nothing Then
cmd.Parameters.AddRange(pms.ToArray())
End If
Using rd = cmd.ExecuteReader()
Try
rd.Read()
output = rd.GetString(0)
rd.Close()
Catch ex As Exception
End Try
End Using
' no need to close when inside a using block
' cn.Close()
End Using
End Using
Return output
End Function
The method now has an optional parameter that will contain the list of the parameters required by the query (or nothing if your query doesn't require parameters). This list is added to the command parameters collection and the query is now executed.
Final Note: Storing passwords in clear text into a database is a well known security problem. I suggest you to search about how to store passwords in a database.
Private Function GetID(User As String, pw As String) As String
Using cmd As New SqlCommand("SELECT ID FROM accounts WHERE accountname =#user AND password=#password", New SqlConnection(SQLConnString))
cmd.Parameters.AddWithValue("#user", User)
cmd.Parameters.Add("#password", SqlDbType.NVarChar)
cmd.Parameters("#password").Value = pw
Try
cmd.Connection.Open()
Return cmd.ExecuteScalar()
Catch ex As Exception
'handle error
Return Nothing
Finally
cmd.Connection.Close()
End Try
End Using
End Function
I've demostrated two methods of setting the parameters. Search for more info or comparison.

How to read a value from mysql database?

I want to be able to read a value (in this case an Group ID). All the topics and tutorials I've watched/read take the data and put it into a textbox.
I don't want to put it in a textbox in this case; I want to grab the Group ID and then say:
If Group ID = 4 then login
Here is an image of the database.
Basically, but none of the tutorials I watch or the multiple forums. None of them take a a value and say if value = 4 then login or do something else.
If text = "1" Then
MysqlConn = New MySqlConnection
MysqlConn.ConnectionString =
"server='ip of server'.; username=; password=; database="
Dim READER As MySqlDataReader
Dim member_group_id As String
Try
MysqlConn.Open()
Dim Query As String
Query = "SELECT * FROM `core_members` where name='" & TextBox2.Text & "'"
Query = "SELECT * FROM `nexus_licensekeys` where lkey_key='" & TextBox1.Text & "'"
COMMAND = New MySqlCommand(Query, MysqlConn)
READER = COMMAND.ExecuteReader
Dim count As Integer
count = 0
While READER.Read
count = count + 1
End While
Here is what I have so far. I'm kind of new implementing mysql data with visual basic and only recently started to get into it. I'm not sure what comes next or how to even start with reading the group id etc.
As I said any help from here on out would be highly appreciated of how to read the group id and say if this group id = this number then do this or that. I'm sure you get the idea.
I divided the code into UI Sub, and Data Access Function that can return data to the UI. Your Event procedure code should be rather brief and the functions should have a single purpose.
Keep your database objects local to the method. This way you can have better control. The Using...End Using blocks ensure that your database objects are closed and disposed even if there is an error.
I leave it to you to add validation code. Checking for empty TextBox or no return of records.
I hope this serves as a quick introduction to using ADO.net. The take away is:
Use Parameters
Make sure connections are closed. (Using blocks)
Private ConnString As String = "server=ip of server; username=; password=; database="
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim GroupID As String = GetGroupID(TextBox1.Text)
If GroupID = "4" Then
'your code here
End If
Dim LocalTable As DataTable = GetLicenseKeysData(TextBox1.Text)
'Get the count
Dim RowCount As Integer = LocalTable.Rows.Count
'Display the data
DataGridView1.DataSource = LocalTable
End Sub
Private Function GetGroupID(InputName As String) As String
'Are you sure member_group_id is a String? Sure looks like it should be an Integer
Dim member_group_id As String = ""
'You can pass the connection string directly to the constructor of the connection
Using MysqlConn As New MySqlConnection(ConnString)
'If you only need the value of one field Select just the field not *
'ALWAYS use parameters. See comment by #djv concerning drop table
Using cmd As New MySqlCommand("SELECT g_id FROM core_members where name= #Name")
'The parameters are interperted by the server as a value and not executable code
'so even if a malicious user entered "drop table" it would not be executed.
cmd.Parameters.Add("#Name", MySqlDbType.VarChar).Value = InputName
MysqlConn.Open()
'ExecuteScalar returns the first column of the first row of the result set
member_group_id = cmd.ExecuteScalar.ToString
End Using
End Using
Return member_group_id
End Function
Private Function GetLicenseKeysData(InputName As String) As DataTable
Dim dt As New DataTable
Using cn As New MySqlConnection(ConnString)
Using cmd As New MySqlCommand("SELECT * FROM `nexus_licensekeys` where lkey_key= #Name;", cn)
cmd.Parameters.Add("#Name", MySqlDbType.VarChar).Value = InputName
cn.Open()
dt.Load(cmd.ExecuteReader())
End Using
End Using
Return dt
End Function

Index was out of bound array exeption in Mysql

I have MySQL table for storing user details which contain 3 columns namely "UserName" ,"password" ,"Access Level". when i try to load details in to VB.net variables it shows " Index was out of bound arrray" Exeption
I am new to mysql please help
I have tried to change the index value of mysqldatareader()
DBConnectionMySql()
myCommandMySql.Connection = myConnectionMySql
myConnectionMySql.Open()
'-----
myCommandMySql.CommandText = "select * from tbl_userregistration where UserName = '" & Trim(Username_TextBox.Text) & "'"
myDataReaderMySql = myCommandMySql.ExecuteReader
If myDataReaderMySql.Read() = Nothing Then
MessageBox.Show("Invalide User Name you Enter!", "Username/Password checker", MessageBoxButtons.OK, MessageBoxIcon.Warning)
Username_TextBox.Focus()
Else
If Username_TextBox.Text = myDataReaderMySql(1) And Password_TextBox.Text = myDataReaderMySql(2) Then
user = Username_TextBox.Text
username = Username_TextBox.Text
Weighing_frm.Show()
Me.Visible = False
Me.Refresh()
Else
MessageBox.Show("Invalide Username Or Password please check and Re-Login!", "Username/Password checker", MessageBoxButtons.OK, MessageBoxIcon.Warning)
Username_TextBox.Focus()
when i try to log in in vb.net form from the loaded data "Index was outside the bounds of the array" error message was shown
Keep you data objects local so you can be sure they are closed and disposed. A Using...End Using block ensures this even if there is an error. You can make your connection string a form level variable so you can use it anywhere but that is the only form level variable you need.
You can pass your connection string directly to the constructor of the connection.
You can pass your sql command text and the connection directly to the constructor of the command.
Please always use Parameters. Not only will it save you from misplacing quotes but it will help ensure that correct datatypes are sent to the database. The most important thing is it helps protect you database from sql injection which can destroy your database. I had to guess at the datatypes in your database. Check the database and adjust the code accordingly.
The DataReader.Read method returns a Boolean so, checking if it returns Nothing is not a valid test. Boolean is a value type so it always returns True or False, never Nothing.
The username is always going to match because that is what you sent to the database in the where clause. As noted in comments by #Jimi, the indexes for the fields returned by the data reader start at 0 so, username would be 0, password 1 and, access level 2. Almost all collections in .net start at index 0.
Why are you using 2 different variables with the same value?
user = Username_TextBox.Text
username = Username_TextBox.Text
What is this supposed to do?
Me.Refresh()
In a real application you would NEVER store passwords as plain text. They would be salted and hashed.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Using cn As New MySqlConnection("Your connection string")
Using cmd As New MySqlCommand("select * from tbl_userregistration where UserName = #UserName;", cn)
cmd.Parameters.Add("#UserName", MySqlDbType.Text).Value = Trim(Username_TextBox.Text)
cn.Open()
Using dr = cmd.ExecuteReader
If dr.HasRows Then
dr.Read()
If Password_TextBox.Text = myDataReaderMySql(1) Then
user = Username_TextBox.Text
Weighing_frm.Show()
Me.Visible = False
Else
MessageBox.Show("Invalide Username Or Password please check and Re-Login!", "Username/Password checker", MessageBoxButtons.OK, MessageBoxIcon.Warning)
Username_TextBox.Focus()
End If
Else
MessageBox.Show("Invalid User Name you Enter!", "Username/Password checker", MessageBoxButtons.OK, MessageBoxIcon.Warning)
Username_TextBox.Focus()
End If
End Using
End Using
End Using
End Sub

Invalid attempt to access a field before calling Read() vb.NET and MySQL

I receive this error every time I try log in with incorrect details which should show a message-box "invalid username..." and when no details are entered it should show "please enter...
conn = New MySqlConnection
conn.ConnectionString = "server=localhost; userid=root; password=...; database=..."
Dim reader As MySqlDataReader
Try
conn.Open()
Dim Query As String
Query = "SELECT Username, Password, Admin FROM appointments.tblLogin WHERE Username='" & TextBox_Username.Text & "' AND Password='" & TextBox_Password.Text & "' "
cmd = New MySqlCommand(Query, conn)
reader = cmd.ExecuteReader
Dim count As Integer
count = 0
While reader.Read
count = count + 1
End While
If reader.GetInt32("Admin") = 1 Then
AdminMainMenu.Show()
Me.Hide()
ElseIf reader.GetInt32("Admin") = 0 Then
MainMenu.Show()
Me.Hide()
Else
MessageBox.Show("Invalid username or password")
End If
If TextBox_Username.Text.Equals("") And TextBox_Password.Text.Equals("") Then
MessageBox.Show("Please enter a username and password")
End If
conn.Close()
Catch ex As MySqlException
MessageBox.Show(ex.GetBaseException.ToString)
Finally
conn.Dispose()
End Try
The MySqlDataReader can move forward-only, once it reaches the end of the rows retrieved by the command, it cannot go back to read previous rows.
The loop used to count the number of rows moves the reader to the end of the data stream. So trying to read the Admin field result in an exception.
If TextBox_Username.Text.Equals("") And _
TextBox_Password.Text.Equals("") Then
MessageBox.Show("Please enter a username and password")
Return
End If
.... opening and executing the command code....
If reader.Read Then
Dim isAdmin = (reader.GetInt32("Admin") = 1)
If isAdmin Then
AdminMainMenu.Show()
Me.Hide()
Else Then
MainMenu.Show()
Me.Hide()
End If
Else
MessageBox.Show("Invalid username or password")
End If
conn.Close()
Notice that I have removed the loop and used a simple if/else statement around the Read method to display the error message and I have changed the reading of the Admin flag creating a boolean variable to simplify the logic inside the true part of the if block.
Said that, you need to look at how build parameterized queries because your string concatenation to build the commandtext exposes your program to Sql Injection Attacks (not to mention syntax errors if some of your textbox contains a single quote, try it...)
Consider also that from a security standpoint you should never store passwords in the database in clear text. Use always an hash of the password