Method not returning anything? - c#

My method for checking login details against a database doesn't seem to return anything. I don't see how it is faulty. Here is the code:
connection.Open();
if (chkRemember.Checked == true)
{
loginDetails();
}
string command = #"SELECT email, password FROM zc_users WHERE email = '#user';";
try
{
// COMMAND DETAILS
MySqlCommand email = new MySqlCommand(command, connection);
// PARAMETERS
email.Parameters.AddWithValue("#user", txtEmail.Text);
// READER DETAILS
MySqlDataReader dr;
// CHECK DETAILS
dr = email.ExecuteReader();
if (dr.Read())
{
string passwordC = dr.GetString(1);
string saltedPass = Security.HashSalt.CreateHash(txtPassword.Text, passwordC);
bool match = IsPasswordMatch(passwordC, saltedPass);
if (match == true)
{
connection.Close();
string email2 = txtEmail.Text;
frmZilent frm = new frmZilent(email2);
frm.Show();
this.Hide();
}
else
{
msgEx m = new msgEx();
m.Show();
connection.Close();
}
}
connection.Close();
}
catch (MySqlException ex)
{
MessageBox.Show("Zilent Error: Code ZCx001. Please report this to the Zilent Team. Thanks. " + ex.Message);
connection.Close();
}
}
Basically, the email and password are selected from the database and then the password in the txtPassword textbox is hashed using the one from the database. The method checks if they are the same, and if they are, it closes the connection and shows the next form.
I either get an error or nothing happens. Any ideas?

Your SQL has the parameter inside a string literal, therefore the parameter is being interpreted as a string literal, so the value won't be used
You have:
SELECT email, password FROM zc_users WHERE email = '#user';
Change to:
SELECT email, password FROM zc_users WHERE email = #user;
Note that the apostrophes are missing in the second version.

Related

Access attributes from the database

In this database table (administration), there are 4 attributes (email, name, password and mobile phone). I need that inside the if I can use each one of them but I don't know how I can access them.
How can I do this?
private void button_login_Click(object sender, EventArgs e)
{
String username, user_password;
username = txt_username.Text;
user_password = txt_password.Text;
try
{
String query = "SELECT * FROM administracao WHERE email = '"+txt_username.Text+"' AND password = '"+txt_password.Text+"'";
SqlDataAdapter sda = new SqlDataAdapter(query, conn);
DataTable dtable = new DataTable();
sda.Fill(dtable);
if (dtable.Rows.Count > 0)
{
// username = txt_username.Text;
// user_password = txt_password.Text;
/* Menuform form2 = new Menuform();
form2.Show();
this.Hide();*/
}
else
{
MessageBox.Show("Invalid Login details", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
txt_username.Clear();
txt_password.Clear();
txt_username.Focus();
}
}
catch
{
MessageBox.Show("Error");
}
finally
{
conn.Close();
}
}
For communication with database I would strongly recommend Entity Framework.
In your case you can use SqlDataReader to get output data from sql query
Code Example:
public void GetData()
{
var query = "your query";
var connectionString = "your connection string";
using (var connection = new SqlConnection(connectionString))
{
var command = new SqlCommand(query, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
// Iterate all selected rows
while (reader.Read())
{
int value1 = (int)reader["Int column name"];
string value2 = (string)reader["String column name"];
}
}
finally
{
reader.Close();
}
}
}
NOTE:
In real project NEVER store passwords as plaintext. How to do it properly
As people already mentioned in the comments, when you decide to execute query directly from the code NEVER combine query like you did, because of SQL Injection. Use parametrized SqlCommands. How to do it

Catching Button Tampering By a User C#

Login Error
As you can see, I want to catch the exception if the user is tampering the Login Button if there are no values in the fields or if it doesn't match info in the database.
For example:
The field has no values and I click Login button once, it says the error. After I clicked OK button, I click Login button again and now it says,
"ExecuteReader requires an open and available Connection. The connection's current state is closed."
I use 3 tier Architecture Windows Application.
BEL:
public SqlDataReader Login(BELLogin bellog)
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = Con.getcon();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT username,password FROM tbl_login WHERE username = #Username AND password = #Password";
cmd.Parameters.AddWithValue("#Username", bellog.Acctname);
cmd.Parameters.AddWithValue("#Password", bellog.Password);
SqlDataReader dr = cmd.ExecuteReader();
return dr;
}
BAL:
public class BELLogin
{
public string Acctname { get; set; }
public string Password { get; set; }
}
DBConnection:
public SqlConnection getcon()
{
if (con.State == System.Data.ConnectionState.Closed)
con.Open();
else if (con.State == System.Data.ConnectionState.Open)
con.Close();
return con;
}
public DataTable ExeReader(SqlCommand cmd)
{
getcon();
cmd.Connection = getcon();
SqlDataReader dr = cmd.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(dr);
return dt;
}
GUI:
private void btn_login_Click(object sender, EventArgs e)
{
BELog.Acctname = txb_accName.Text;
BELog.Password = txb_password.Text;
SqlDataReader dr;
dr = BALog.Login(BELog);
if (txb_accName.Text == "" || txb_password.Text == "")
{
MessageBox.Show("Some fields are empty. Please fill up all fields before clicking LOGIN button.", "Login Status", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
if (dr.HasRows == true)
{
dr.Read();
Inventory Inv = new Inventory();
Inv.Show();
this.Hide();
}
else
{
MessageBox.Show("You have entered your password or account name incorrectly. Please check your password and account name and try again.", "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
dr.Close();
}
Logging in is ok but what if the user tampering the button?
Thank you for helping me :D
You need to change your code in gui like this:
//Put code to get the reader inside else clause and close the reader in the same else clause. Also ideally you should return if you encounter. I have added it and commented it.
//Off course you would need to put more effort to make this code better. You will get to that as you get more experience. For now this should make your app work.
private void btn_login_Click(object sender, EventArgs e)
{
BELog.Acctname = txb_accName.Text;
BELog.Password = txb_password.Text;
if (txb_accName.Text == "" || txb_password.Text == "")
{
MessageBox.Show("Some fields are empty. Please fill up all fields before clicking LOGIN button.", "Login Status", MessageBoxButtons.OK, MessageBoxIcon.Error);
//return;
}
else
{
SqlDataReader dr;
dr = BALog.Login(BELog);
if (dr.HasRows == true)
{
dr.Read();
Inventory Inv = new Inventory();
Inv.Show();
this.Hide();
}
else
{
MessageBox.Show("You have entered your password or account name incorrectly. Please check your password and account name and try again.", "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
dr.Close();
}
}
Do not reuse connections like this, it is bad practice and unnecessary.
Wrap all type instances that implement IDisposable in using blocks so the resources are released. In your case SqlConnection, SqlCommand, SqlDataReader, DataTable.
From a security standpoint you should never store your user passwords (anywhere, not DB, not files, not registry, etc. just do not store them). You need to store the hash, not the password, and compare hashes
Adhere to loose the coupling / high cohesion principle. Essentially expose as little as possible (especially implementation details) from your methods / classes so they can be easily reused and changed. Currently you are passing around and sharing DB objects, this will make your code brittle and very difficult to track down where problems are. Here is your code with a little bit of refactoring, notice that if you have another issue with a connection during login it would now be very easy to figure out where that might be.
// place in new code file
public class UserManager{
public BELLogin FindLogin(string userName, string password){
if(string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
return null;
using(var connection = new SqlConnection("connectionStringPointerFromAppConfigHere"))
using(SqlCommand cmd = new SqlCommand("SELECT username,password FROM tbl_login WHERE username = #Username AND password = #Password", connection))
{
connection.Open();
cmd.Parameters.AddWithValue("#Username", bellog.Acctname).SqlDbType = SqlDbType.VarChar;
// BAD practice! Use a secure hash instead and store that not the password!
cmd.Parameters.AddWithValue("#Password", bellog.Password).SqlDbType = SqlDbType.VarChar;
using(SqlDataReader dr = cmd.ExecuteReader())
{
if(dr.Read())
return new BELLogin() {Acctname = dr.GetString(0), Password = dr.GetString(1)}; // passed in is same as in datareader
}
}
return null;
}
}
From your login form class
private void btn_login_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txb_accName.Text) || string.IsNullOrEmpty(txb_password.Text))
{
MessageBox.Show("Some fields are empty. Please fill up all fields before clicking LOGIN button.", "Login Status", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
var manager = new UserManager();
var user = manager.FindLogin(txb_accName.Text, txb_password.Text);
if (user != null)
{
Inventory Inv = new Inventory();
Inv.Show();
this.Hide();
}
else
{
MessageBox.Show("You have entered your password or account name incorrectly. Please check your password and account name and try again.", "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
Your btn_login_Click method appears to call BALog.Login(BELog) prior to checking if there are any valid values in the username and password textboxes. Simply move the validation to the top of btn_login_Click method, and return if the fields are empty:
if (txb_accName.Text == "" || txb_password.Text == "")
{
MessageBox.Show("Some fields are empty. Please fill up all fields before clicking LOGIN button.", "Login Status", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
The code in the else portion of that if statement can stay where it is, just not inside an else. The method will exit due to return statement if there are no valid values in the username and password textboxes.
As others have suggested, you should review your code to ensure you really want this structure; but if you do want to keep it that way, this simple fix will solve your problem.
Just get rid of your DBConnection object, it's not really doing anything and just making your structure complex:
public BELLogin Login(BELLogin bellog)
{
SqlConnection conn = new SqlConnection(connectionsString);
try
{
using (SqlCommand cmd = new SqlCommand())
{
conn.Open();
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT username,password FROM tbl_login WHERE username = #Username AND password = #Password";
cmd.Parameters.AddWithValue("#Username", bellog.Acctname);
cmd.Parameters.AddWithValue("#Password", bellog.Password);
//really this should be in a using as well.
//You be better off reading your data
//into a class and returnig the class not the reader.
using (SqlDataReader dr = cmd.ExecuteReader())
{
BELLogin obj = new BELLogin();
while(dr.Read())
{
//populate obj
}
return obj;
}
}
}
finally
{
conn.Close();
conn.Dispose();
}
}
also the way you use it can cause memory leaks as your not explicitly disposing and closing your connections. Always dispose Sql objects in C#. Be wary of exceptions too. Any exceptions in your code will not close the connection, etc. This will result in memory leaks and connections locking

C# winform login using Ms Access 2013

I am creating a C# windows login form using MS Access 2013.
Login form using User ID(Autonumber) and Password(Short text).
My problem here is, it always crash(or Syntax error I guess) every time I click the LOGIN button and I can't trace the problem since I'm still inexperience in programming.
Table User
Fields: user_Id(Auto Number), password(short text), name(short text), type(number)
private void btn_Login_Click(object sender, EventArgs e)
{
try
{
if (string.IsNullOrEmpty(txt_UserId.Text))
{
lbl_warningUser.Visible = true;
lbl_warningUser.Text = "User ID is Empty";
}
if (string.IsNullOrEmpty(txt_Password.Text))
{
lbl_warningPass.Visible = true;
lbl_warningPass.Text = "Password is Empty";
}
if (txt_UserId.Text !="" & txt_Password.Text != "")
{
string constring = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Database/Health.accdb;";
string query = ("SELECT COUNT(*) FROM User WHERE user_Id = #ID AND password = #Pass");
using (OleDbConnection con = new OleDbConnection(constring))
using (OleDbCommand cmd = new OleDbCommand(query, con))
{
con.Open();
cmd.Parameters.AddWithValue("#ID", txt_UserId.Text);
cmd.Parameters.AddWithValue("#Pass", txt_Password.Text);
int result = (int)cmd.ExecuteScalar();
if (result > 0)
{
MessageBox.Show("Successfully Login");
con.Close();
this.Hide();
MainUI m = new MainUI();
m.Show();
}
else
{
MessageBox.Show("Incorrect User ID or Password");
}
con.Close();
}
}
}
catch (Exception ex)
{
MessageBox.Show(" "+ex);
}
}
User is a reserved word in MS Access I think, so you need to wrap it in square bracket delimiters. Also, you likely need to specify an alias for the COUNT function result:
"SELECT COUNT(*) AS qtyUsers FROM [User] WHERE user_Id = #ID AND password = #Pass"
txt_UserId.Text has a default return value of string, did you convert the value to an integer then try actually autonumber is integer.
First convert your value and try
Convert.ToInt32(txt_UserId.Text)

How to Display Messagebox When No Values Found on SQL

Following is a code to get values from table in sql and set it to relevant fields. However i want to know how to write if condition in below block code so if the datatable contains the USERID it will performs function below but if it didn't find the USERID it should popup a error message saying no User Found.
SqlCommand myCommand = new SqlCommand
("SELECT * From USER_TABLE WHERE USERID =" + userIdTextBox.Text, con1);
myReader = myCommand.ExecuteReader();
while (myReader.Read())
{
nameTextBox.Text = (myReader["FIRST_NAME"].ToString());
lnameTextBox.Text = (myReader["LAST_NAME"].ToString());
posTextBox.Text = (myReader["POSITION"].ToString());
emailTextBox.Text = (myReader["E_MAIL"].ToString());
phoneTextBox.Text = (myReader["PHONE"].ToString());
usernameTextBox.Text = (myReader["USERNAME"].ToString());
userLevelTextBox.Text = (myReader["USER_LEVEL"].ToString());
string filename = (myReader["PROFILE_PICTURE"].ToString());
profilePicBox.Load(filename);
}
You need to check if(myReader.HasRows)
if(MyReader.HasRows)
{
while (myReader.Read())
{
//your code here.
}
}
else
{
// your alert.
}
if (myReader.Read()) //assuming you only ever have a single result...
{
//set form fields.
}
else
{
//message box
}
Edit based on comment from #dmitry-bychenko

MySqlCommand: no rows returned

I have a database created in a server and I added a row by MySql query browser for testing. This row is visible either with PhpMyAdmin or MySql query browser.
But when I want to reach this table within my program it says me there is no rows (reader.HasRows = false)
cs is the connection string in PublicVariables class
Here is the code
public static int checkuser(string myuser, string mypass)
{
try
{
using (MySqlConnection conn = new MySqlConnection(PublicVariables.cs))
{
string MypassMd5 = MakeMD5(mypass);
conn.Open();
if (conn == null)
Environment.Exit(0);
using (MySqlCommand cmd =
new MySqlCommand("SELECT username, password " + "FROM Users WHERE username = 'myuser'" ,conn))
{
using (MySqlDataReader reader = cmd.ExecuteReader())
{
//DateTime mytime = DateTime.Now ;
if (reader.HasRows)
{
if (Convert.ToString(reader["password"]) != MypassMd5)
{
reader.Close();
conn.Close();
return -1;
}
else
{
PublicVariables.UserId = Convert.ToString(reader["username"]);
PublicVariables.UserDegre = Convert.ToInt16(reader["userdegre"]);
conn.Close();
reader.Close();
return 1;
}
}
else
{
reader.Close();
conn.Close();
return 2;
}
}
}
}
}
catch (MySqlException ex)
{
MessageBox.Show(ex.ToString());
}
return 0;
}
What's wrong in my code?
Well the primary error is in your command string , myuser is a variable and you cannot pass its value putting the variable name inside quotes.
new MySqlCommand("SELECT username, password FROM Users WHERE username = 'myuser'" ,conn)
instead this line should be converted to use a parameterized query
string commandText = "SELECT username, password, userdegre FROM Users WHERE username = #uname";
using (MySqlCommand cmd = new MySqlCommand(commandText ,conn)
{
cmd.Parameters.AddWithValue("#uname", myuser);
....
Looking at your code you have another error after this. You try to read the field userdegre, but this field is not retrieved by your query, so you need to add it to the list of retrieved fields.
But the only field you really need to know is userdegre because you already know the username and the password, so you could remove the datareader and use ExecuteScalar and pass the username and the password as parameters for the WHERE clause. If you get anything in return then you are sure that your user is authenticated by the database.
string commandText = "SELECT userdegre FROM Users WHERE username = #uname AND Password =#pwd";
using(MySqlCommand cmd = new MySqlCommand( commandText ,conn))
{
cmd.Parameters.AddWithValue("#uname", myuser);
cmd.Parameters.AddWithValue("#pwd", MypassMd5);
var result = cmd.ExecuteScalar();
if(result != null)
{
PublicVariables.UserId = myuser;
PublicVariables.UserDegre = result.ToString();
}
}
Don't check reader.HasRows. You need to call reader.Read(), and check the result of that.
Also, some side issues:
MD5 is incredibly weak for a password hash. Really. Just don't use it for that. Look into bcrypt as a much better alternative. Better still if you're not writing authentication code yourself at all. Look for a library for help to get this stuff right... it's just so easy to write authentication code that seems to work, passes all your tests, but has a subtle flaw that gets you hacked a few months down the road.
No need to call conn.Close(). That's what your using blocks are for. They will handle this for you.
I'd remove the try/catch as well. Since you're already returning error conditions to the calling code, I'd leave that as the place where errors are processed, such that your try/catch should go at that level.
You're looking for userdegre in the results that was not in the select list.
Parameterized queries are your friend.
Put it all together you and you end up with this:
public static int checkuser(string myuser, string mypass)
{
string passHash = BCrypt(mypass); //Need to get bcyrpt library and make the function
using (MySqlConnection conn = new MySqlConnection(PublicVariables.cs))
using (MySqlCommand cmd =
new MySqlCommand("SELECT username, password, userdegre FROM Users WHERE username = #user" ,conn))
{
cmd.Parameters.Add("#user", SqlDbType.NVarChar, 20).Value = myuser;
conn.Open();
using (MySqlDataReader reader = cmd.ExecuteReader())
{
if (!reader.Read()) return 2;
if (Convert.ToString(reader["password"]) != MypassMd5) return -1;
PublicVariables.UserId = Convert.ToString(reader["username"]);
PublicVariables.UserDegre = Convert.ToInt16(reader["userdegre"]);
return 1;
}
}
}
I would try something like this new MySqlCommand("SELECT username, password, userdegre " + "FROM Users WHERE username = 'myuser'" ,conn))
adding userdegre the column name in your select statement.
Finally for c# 2008 net 3.5 WORKING COPY of this after the help of #Joel and # Steve is as this:
public static int usertrue(string myuser, string mypass)
{
try
{
using (MySqlConnection conn = new MySqlConnection(PublicVariables.cs))
{
string MypassMd5 = MakeMD5(mypass);
using (MySqlCommand cmd =
new MySqlCommand("SELECT username, password ,userdegre FROM Users WHERE username = #user",conn))
{
cmd.Parameters.Add("#user", MySqlDbType.VarChar, 15).Value = myuser;
conn.Open();
using (MySqlDataReader reader = cmd.ExecuteReader())
{
if (!reader.Read()) return 2;
if (Convert.ToString(reader["password"]) != MypassMd5) return -1; {
PublicVariables.UserId = Convert.ToString(reader["username"]);
PublicVariables.UserDegre = Convert.ToInt16(reader["userdegre"]);
return 1;
}
}
}
}
}

Categories

Resources