C# Mysql datareader - how to get other coloumn using datareader - c#

Im trying to validate the password from my database that has been hash and salted. I Created an column in my user table username, hash and salt. Now i want to know i can i access the other column value using datareader.
I tried this method but i got an red line. also this is my failed attempt
public static bool VerifyPassword(string enteredPassword, string storedHash, string storedSalt)
{
var saltBytes = Convert.FromBase64String(storedSalt);
var rfc2898DeriveBytes = new Rfc2898DeriveBytes(enteredPassword, saltBytes, 10000);
return Convert.ToBase64String(rfc2898DeriveBytes.GetBytes(256)) == storedHash;
}
private void bunifuFlatButton1_Click(object sender, EventArgs e)
{
string userhash;
string usersalt;
MySqlConnection mysqlCon = new MySqlConnection(connectionString);
MySqlCommand cmd = new MySqlCommand("SELECT * FROM login.info WHERE username = #user", mysqlCon);
MySqlDataReader rd;
rd = cmd.ExecuteReader();
cmd.Parameters.Add("#user", MySqlDbType.VarChar).Value = username.Text;
mysqlCon.Open();
while (rd.Read())
{
userhash = rd.GetString("hash");
usersalt = rd.GetString("salt");
bool isPasswordMatched = VerifyPassword(textpass.Text, userhash.Hash, usersalt.Salt);
// i got redline error in here. i only follow instruction.. link below
if (isPasswordMatched)
{
//Login Successfull
}
else
{
//Login Failed
}
}
}
by the way, i only follow this instruction from this thread. How to validate salted and hashed password in c#

Here is another way of writing your code, not really an answer, but...not perfect mind, but at least it will dispose of the objects and also call them in the correct order. Please read upon on IDisposable and Sql Injection.
private void bunifuFlatButton1_Click(object sender, EventArgs e)
{
using (MySqlConnection mysqlCon = new MySqlConnection(connectionString))
{
// Use a named list of fields please. And cleanse the text.
using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM login.info WHERE username = #user", mysqlCon))
{
cmd.Parameters.Add("#user", MySqlDbType.VarChar).Value = username.Text; // Let's hope user name is not Jimmy DropTables!!
mysqlCon.Open();
using (MySqlDataReader rd = cmd.ExecuteReader())
{
while (rd.Read())
{
string userhash = rd.GetString("hash");
string usersalt = rd.GetString("salt");
bool isPasswordMatched = VerifyPassword(textpass.Text, userhash, usersalt);
// Note that we are passing in strings, not props of an unknown object
if (isPasswordMatched)
{
//Login Successfull
}
else
{
//Login Failed
}
}
}
mysqlCon.Close();
}
}
}

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

Why do I have to click twice to execute method in Label MouseDown event

I'm working on an assignment for College and the requirements are that I have to use multi-threading, now everytime I login, I have to click twice to change the UI for the MainWindow. Any idea what I might be doing wrong?
If I use the code from the user_login method it works fine, UI updates quickly, but when I use multi-threading I have to click the label twice in order to change my UI.
I've done the same using a button control but also has the same result for both tests given above.
private void tbLogin_MouseDown(object sender, MouseButtonEventArgs e)
{
//Assign Class Property Values
login.Student_Email = txtstd_Email.Text;
login.Student_Password = txtstd_Password.Password;
Thread user_login_thread = new Thread(() => User_Login(login.Student_Email,
login.Student_Password));
user_login_thread.Start();
if (login.UserLoggedIn)
{
foreach (Window window in Application.Current.Windows)
{
if (window.GetType() == typeof(MainWindow))
{
//Change page on login
(window as MainWindow).frmView.Source = new Uri("Views/Dashboard.xaml", UriKind.Relative);
}
}
}
user_login_thread.Join();
if (chkRemember.IsChecked == true)
{
Properties.Settings.Default.Student_Email = login.Student_Email;
Properties.Settings.Default.Student_Password = login.Student_Password;
Properties.Settings.Default.Save();
}
}
private void User_Login(string email, string password)
{
//Security object
Secure security = new Secure();
conn.Open();
string sql = "SELECT Student_Number, Student_FullName, Student_Email, Student_Password FROM
Student_Data WHERE Student_Email=#Email";
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.Add("#Email", System.Data.SqlDbType.VarChar, 55).Value = email;
cmd.Parameters.Add("#Pass", System.Data.SqlDbType.VarChar, 55).Value = password;
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read() &&
login.Student_Password.Equals(security.Decrypt(reader["Student_Password"].ToString())))
{
login.UserLoggedIn = true;
}
else
{
_ = MessageBox.Show("Login Unsuccessful", "Student Login Unsuccessfull",
MessageBoxButton.OKCancel, MessageBoxImage.Error);
}
}
conn.Close();
}
The primary issue is that you are not waiting for the query to finsih before checking if (login.UserLoggedIn).
I'd advise you to use async and await for this instead of threading.
You have some other issues also:
connection and reader objects need using blocks.
Do not cache the connection, create a new one when you need it.
Reversible encryption on a password is a bad idea, use hashing instead. Pass the hash to the server for it to verify, don't bring it back to the client app.
Don't block the thread with message boxes while the connection is open.
Don't read more columns than you need.
If you only have one column and row use ExecuteScalar
private async void tbLogin_MouseDown(object sender, MouseButtonEventArgs e)
{
//Assign Class Property Values
login.Student_Email = txtstd_Email.Text;
login.Student_Password = txtstd_Password.Password;
await User_Login(login.Student_Email, login.Student_Password));
.....
private async Task User_Login(string email, string password)
{
//Security object
Secure security = new Secure();
const string sql = #"
SELECT 1
FROM Student_Data
WHERE Student_Email = #Email
AND Student_Password = #Pass;
";
using (var conn = new SqlConnection(yourConnString))
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.Add("#Email", SqlDbType.VarChar, 55).Value = email;
cmd.Parameters.Add("#Pass", SqlDbType.VarChar, 55).Value = security.Encrypt(password);
await conn.OpenAsync();
login.UserLoggedIn = await comm.ExecuteScalarAsync() != null;
}
if (!login.UserLoggedIn)
{
_ = MessageBox.Show("Login Unsuccessful", "Student Login Unsuccessfull",
MessageBoxButton.OKCancel, MessageBoxImage.Error);
}
}

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;
}
}
}
}
}

execute reader doesn't respond

i have a php code.here is the code,i gonna to translate it to .NET but in some point i'm getting some trouble.
function processInput($conn, $MessageArray, $mobilenumber, $date, $odd)
{
$strSQLUSER="SELECT * FROM tbl_tiduser WHERE username='".addslashes($MessageArray[0])."' AND stat!='1' AND stat!='4'";
$result_user=odbc_exec($conn,$strSQLUSER) or die("Could not connect to database");
here is the converted .NET code
public class ProcessInput
{
private string msg_arr;
private string MooseSeenInput(string MobileNo,string Date,string odd,params Array[] msg_arr)
{
SqlCommand com = new SqlCommand("SELECT * FROM tbl_tiduser WHERE username=#username AND stat!='1' AND stat!='4'", mycon);
com.Parameters.AddWithValue("#username",username);
using (SqlDataReader reader = com.ExecuteReader())
// whats the next part need to come here ???
}
this is incomplete.i'm not going to compile it....
private static void ReadOrderData(string connectionString)
{
string queryString =
"SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlCommand command =
new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// Call Read before accessing data.
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
// Call Close when done reading.
reader.Close();
}
}
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.aspx
I would use something like this to get the column(s) you're after:
string username = null;
using (SqlDataReader reader = com.ExecuteReader()) {
if (reader.read()) {
username = (string)reader["mydbcolumnname"];
}
reader.Close();
}
Note that if you want to pull all the result rows (as opposed to stepping through them) then you'd normally use a SqlDataAdapter to fill a DataSet (instead of the reader), eg:
string username;
using (SqlDataAdapter adapter = new SqlDataAdapter(com))
{
using (DataSet ds)
{
adapter.Fill(ds);
username = (string)ds.Tables[0].Rows[0]["mycolumnname"];
}
}
I'm all for easy; I would write a class that mirrors the record I'm reading, i.e.
public class User {
public int Id {get;set;}
public string Name {get;set;}
}
and use "dapper":
var user = myCon.Query<User>(
"SELECT * FROM tbl_tiduser WHERE username=#username AND stat not in ('1','4')",
new {username}).SingleOrDefault();
if(user == null) { /* not found, presumably throw an exception */ }
string name = user.Name; // etc
Then you don't need to mess with commands, readers, parameters etc (see how the username is being made into a db parameter cleanly?).

Use ContentEditable to Save Into DB With ASP.NET?

I'm trying to create a web page where a user can edit the text and when they are done, they hit save and the new text entered is saved into the database.
I'm not getting any errors in my code, but for some reason, the old text is just being rewritten into the db instead of the new text.
Here is my code-behind:
protected void saveBtn_Click(object sender, EventArgs e)
{
string newName;
string newIntro;
string newEduc;
string newWork;
h1New.Text = h1.Text;
newName = h1New.Text;
newIntro = intro.Text;
newEduc = educ.Text;
newWork = employ.Text;
string connectionInfo = ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionInfo))
{
connection.Open();
SqlCommand myCommand = new SqlCommand("UPDATE simpleContent SET userName = #newName, infoContent = #newIntro, educContent = #newEduc, workContent = #newWork WHERE userID = #userName", connection);
try
{
string username = HttpContext.Current.User.Identity.Name;
myCommand.Parameters.AddWithValue("#userName", username.ToString());
myCommand.Parameters.AddWithValue("#newName", newName.ToString());
myCommand.Parameters.AddWithValue("#newIntro", newIntro.ToString());
myCommand.Parameters.AddWithValue("#newEduc", newEduc.ToString());
myCommand.Parameters.AddWithValue("#newWork", newWork.ToString());
myCommand.ExecuteNonQuery();
connection.Close();
}
catch
{
Response.Redirect("http://www.google.co.uk");
}
}
}
I would appreciate any pointers that you may have.
try to put you code in format:
protected void saveBtn_Click(object sender, EventArgs e)
{
// add variables
string connectionInfo = (...)
string commandText = (...)
using (...){
SqlCommand myCommand = (...)
// add parameters
try
{
connection.Open();
myCommand.ExecuteNonQuery();
connection.Close();
}
catch (Exception ex)
{
(...)
}
}

Categories

Resources