I'm just a beginner in C#. I'm using XAMPP server for MySQL database and Visual C# 2010. Then I have created a database named "testdb" in phpMyAdmin and a table named "login". I have inserted my username and password in the table. I'm doing a simple WinForm login where I made two text boxes for username and password and a button. I have my codes done and there's no compiler error. But I had troubled in one line. It says "Unable to connect to any of the specified MySQL hosts". I added MySql.Data to my references. I want to fetch the data in the database table when I'm going to log in. Then authorize the user or if not matched, it will prompt an error message.
Here is my code:
using MySql.Data.MySqlClient;
public bool Login(string username, string password)
{
MySqlConnection con = new MySqlConnection("host=localhost;username…");
MySqlCommand cmd = new MySqlCommand("SELECT * FROM login WHERE username='" +
username + "' AND password='" + password + "';");
cmd.Connection = con;
con.Open(); // This is the line producing the error.
MySqlDataReader reader = cmd.ExecuteReader();
if (reader.Read() != false)
{
if (reader.IsDBNull(0) == true)
{
cmd.Connection.Close();
reader.Dispose();
cmd.Dispose();
return false;
}
else
{
cmd.Connection.Close();
reader.Dispose();
cmd.Dispose();
return true;
}
}
else
{
return false;
}
}
*I hope for your your feedback. :)
Your immediate problem is probably either an incorrect connection string or the database server is not available. The connection string should be something like this
Server=localhost;Database=testdb;Uid=<username>;Pwd=<password>;
with <username> and <password> replaced with your actual values.
Besides that your code has several issues and you should definitely look into them if this is intended to become production code and probably even if this is just a toy project to learn something. The list is in particular order and may not be comprehensive.
Do not hard code your connection string. Instead move it to a configuration file.
Do not include plain text passwords in configuration files or source code. There are various solutions like windows authentication, certificates or passwords protected by the Windows Data Protection API.
Do not just dispose IDisposable instances by calling IDisposable.Dispose(). Instead use the using statement to release resources even in the case of exceptions.
Do not build SQL statements using string manipulation techniques. Instead use SqlParameter to prevent SQL injection attacks.
Do not store plain text passwords in a database. Instead at least store salted hashes of the passwords and use a slow hash function, not MD5 or a member of the SHA family.
You can use IDbCommand.ExecuteScalar to retrieve a scalar result and avoid using a data reader.
Comparing a boolean value with true or false is redundant and just adds noise to your code. Instead of if (reader.IsDBNull(0) == true) you can just use if (reader.IsDBNull(0)). The same holds for if (reader.Read() != false) what is equivalent to if (reader.Read() == true) and therefore also if (reader.Read()).
Using an O/R mapper like the Entity Framework is usually preferred over interacting with the database on the level of SQL commands.
Try modifying your ConnectionString accordingly to the Standard MySQL ConnectionString:
Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;
Source:
MySQL ConnectionStrings
You can also take a look at the following link, that shows how to connect to a MySQL database using C#:
Creating a Connector/Net Connection String (MYSQL)
Make it simple and sql injection free, and also don't forget to add MySql.Web
in your references since your using XAMPP
public bool Login(string username, string password)
{
DataTable dt = new DataTable();
string config = "server=....";
using (var con = new MySqlConnection { ConnectionString = config })
{
using (var command = new MySqlCommand { Connection = con })
{
con.Open();
command.CommandText = #"SELECT * FROM login WHERE username=#username AND password=#password";
command.Parameters.AddWithValue("#username", username);
command.Parameters.AddWithValue("#password", password);
dt.Load(command.ExecuteReader());
if (dt.Rows.Count > 0)
return true;
else
return false;
} // Close and Dispose command
} // Close and Dispose connection
}
Related
I have a software which displays some tables from our SQL database. Now I want to add a tool, where I can change the password for my "testdummy" user.
I tried to open a connection again but it didn't help. If you need some additional code or informations, just write a comment.
Notice that I'm new to programming. I'm a apprentice and currently learning programming and administer databases. I know this is not the safest solution, but it's just a little task from my instructor. This software will not be released for customers.
Like I mentioned before, I tried to open a connection again before I want to change the password.
public void Change()
{
SqlConnection con = new SqlConnection();
string connectionString = GetConnectionString();
if (NewPassword.Password == NewPasswordAgain.Password && OldPassword.Password == GlobalData.Password)
{
try
{
//dbMan.TryConnect(connectionString);
//con.Open();
SqlConnection.ChangePassword($"Data Source={GlobalData.ServerName};Initial Catalog={GlobalData.DBName};UID={GlobalData.Username};PWD={OldPassword}", $"{NewPassword}");
}
catch (SqlException ex)
{
MessageBox.Show("Unable to change password. Try again!" + ex);
}
}
else
{
// If new Password doesn't match.
MessageBox.Show("Passwords doesn't match!");
}
}
I'm getting a SQL exception when I am trying to change the password.
(System.Data.SqlClient.SqlException (0x80131904): Login failed for user 'csharptest'.
I get this at:
SqlConnection.ChangePassword($"Data Source={GlobalData.ServerName};Initial Catalog={GlobalData.DBName};UID={GlobalData.Username};PWD={OldPassword}", $"{NewPassword}");
At this point of the programm, there should be a connection to the database, because I can handle some tables and manipulate the data sets.
But when I uncomment this:
//dbMan.TryConnect(connectionString);
//con.Open();
It goes into the catch brackets there:
public bool TryConnect(string connectionString)
{
conn = new SqlConnection();
conn.ConnectionString = connectionString;
try
{
conn.Open();
return true;
}
catch (Exception)
{
MessageBox.Show("Couldn't connect");
return false;
}
}
and returns following exception:
System.InvalidOperationException: 'Die ConnectionString-Eigenschaft wurde nicht initialisiert.'
In english it should be something like: "the connectionstring property has not been initialized"
Edit:
In the logs I'm getting this:
Login failed for user 'csharptest'. Reason: Password did not match that for the login provided.
Edit:
Instead of:
SqlConnection.ChangePassword($"Data Source={GlobalData.ServerName};Initial Catalog={GlobalData.DBName};UID={GlobalData.Username};PWD={OldPassword}", $"{NewPassword}");
I did this:
string updatePassword = "USE CSHARPTEST ALTER LOGIN [" + GlobalData.Username + "] WITH PASSWORD = '" + NewPassword + "'";
con.Open();
cmd.ExecuteNonQuery();
And now I think the only problem is the permission on the server.
You need to use parameters at the DbContext level. See this answer for more details, but, here's a code example (adapted from that same page):
string sql = "ALTER LOGIN #loginName WITH PASSWORD = #password";
ctx.Database.ExecuteSqlCommand(
sql,
new SqlParameter("loginName", loginName),
new SqlParameter("password", password));
The purpose of using the parameters here (and everywhere) is to prevent a SQL injection attack. This is especially important given that you are writing code that changes a password.
UPDATE
The ALTER LOGIN statement won't work with variables; it must be done through dynamic SQL. Here's an example of the updated code:
string sql = #"DECLARE #sql NVARCHAR(500)
SET #sql = 'ALTER LOGIN ' + QuoteName(#loginName) +
' WITH PASSWORD= ' + QuoteName(#password, '''')
EXEC #sql ";
ctx.Database.ExecuteSqlCommand(
sql,
new SqlParameter("loginName", loginName),
new SqlParameter("password", password));
Note we're still using the SqlParameters to prevent SQL injection attacks. We are also using the T-SQL method QuoteName to do proper quoting in the SQL we are generating; but this method simply doubles any [ characters (in the first call) or ' characters (in the second). There are many other vectors for a SQL injection attack, so merely relying on QuoteName wouldn't be enough.
I am trying to learn C# and I'm writing a system where you have to log in, I'm storing the data in a database and loading in with code. The data is loaded in with no errors and I can Console.WriteLine it and it's all fine, but when I run comparison on it it always fails. Here is the relevant code.
Edit: I have tried without using the $ in the string comparison and it still doesn't work
private void login_button_Click(object sender, EventArgs e)
{
// App.config stores configuration data
// System.Data.SqlClient provides classes
// for accessing a SQL Server DB
// connectionString defines the DB name, and
// other parameters for connecting to the DB
// Configurationmanager provides access to
// config data in App.config
string provider = ConfigurationManager.AppSettings["provider"];
string connectionString = ConfigurationManager.AppSettings["connectionString"];
// DbProviderFactories generates an
// instance of a DbProviderFactory
DbProviderFactory factory = DbProviderFactories.GetFactory(provider);
// The DBConnection represents the DB connection
using (DbConnection connection =
factory.CreateConnection())
{
// Check if a connection was made
if (connection == null)
{
Console.WriteLine("Connection Error");
Console.ReadLine();
return;
}
// The DB data needed to open the correct DB
connection.ConnectionString = connectionString;
// Open the DB connection
connection.Open();
// Allows you to pass queries to the DB
DbCommand command = factory.CreateCommand();
if (command == null)
{
return;
}
// Set the DB connection for commands
command.Connection = connection;
// The query you want to issue
command.CommandText = $"SELECT * FROM Users WHERE Username = '{username_input.Text}'";
// DbDataReader reads the row results
// from the query
using (DbDataReader dataReader = command.ExecuteReader())
{
dataReader.Read();
//while(dataReader.Read())
//{
if ($"{password_input.Text}" ==$"{dataReader["Password"]}")
{
MessageBox.Show("Logged in");
}
else
{
MessageBox.Show("Invalid Credentials!");
}
//}
}
}
}
}
Always use parameters instead of string concatenation in your queries. It guards against sql injection (not applicable to MS Access) and ensures you never has issues with strings that contain escape charaters.
I notice you probably have password as plain text, never store passwords in plain text!
In this particular case using ExecuteScalar simplifies the logic (IMO). If you were to want to return data and read it using a data reader then do not use * for your return. Specify your column names instead. This will guard your code against schema changes like columns being added or column order changes.
command.CommandText = "SELECT [Password] FROM [Users] WHERE [Username] = #userName";
// using DbCommand adds a lot more code than if you were to reference a non abstract implementation when adding parameters
var param = command.CreateParameter();
param.ParameterName = "#userName";
param.Value = username_input.Text;
param.DbType = DbType.String;
param.Size = 100;
command.Parameters.Add(param);
// compared with SqlDbCommand which would be 1 line
// command.Parameters.Add("#userName", SqlDbType.VarChar, 100).Value = username_input.Text;
var result = command.ExecuteScalar()?.ToString();
if(string.Equals(password_input.Text, result, StringComparison.Ordinal))
MessageBox.Show("Logged in");
else
MessageBox.Show("Invalid Credentials!");
Start off on the right foot with learning C# with some advice Ive seen in the comments already as well some additional advice below:
Parameterize your queries at the very minimum
The below way is Open to SQL injection
command.CommandText = $"SELECT * FROM Users WHERE Username = '{username_input.Text}'";
This instead should be written as: (Keep in mind there are shorter ways to write this but I'm being explicit since you are learning)
var usernameParam = new SqlParameter("username", SqlDbType.VarChar);
usernameParam.Value = username_input.Text;
command.Parameters.Add(usernameParam);
command.CommandText = "SELECT * FROM Users WHERE Username = #username";
Secondly, debugging is your friend. You need to add a breakpoint on the line that is failing and utilize the built in Visual Studio Watchers to look at your variables. This will tell you more information than a console.writeline() and solve more problems than you might imagine.
I am just learning c# and sql server. This question has been asked a couple of times but the solutions posted don't seem to help me.
I have a table called "LoginInfo" that has a user's "email" and "pass".
In visual studio i have this method that checks a users login information
private boolean dbQueryLogin(string email, string password)
{
string com = "SELECT pass FROM LoginInfo WHERE email = XXXXX#yahoo.com";
SqlCommand command = new SqlCommand(com, conn);
SqlDataReader reader = command.ExecuteReader();
return reader.GetString(0).Equals(password);
}
This keeps on throwing the error "Additional information: The multi-part identifier "XXXX.edu" could not be bound."
The syntax looks right to me, is there anything i'm missing??
The clue is in the error message:
The multi-part identifier "XXXX.edu" could not be bound.
That strongly suggests that the problem isn't with identifying your table - it's with the bit that ends with "edu", which seems like to be an email address.
The immediate problem is that you've forgotten to quote a value. The deeper problem is that you should be using parameterized SQL anyway, to avoid SQL injection attacks, conversion problems and unreadable code. Given that the value you've given in the same code isn't the same as what's in the error message, I suspect you really have code like:
string sql = "SELECT pass FROM LoginInfo WHERE email = " + email;
Don't do that. Use parameterized SQL instead:
private boolean dbQueryLogin(string email, string password)
{
string sql = "SELECT pass FROM LoginInfo WHERE email = #email";
using (var connection = new SqlConnection(connectionString))
{
using (var command = new SqlCommand(sql))
{
command.Parameters.Add("#email", SqlDbType.NVarChar).Value = email;
using (var reader = command.ExecuteReader())
{
// FIXME: What do you want to do if
// there are no matches?
reader.Read();
return reader.GetString(0) == password;
}
}
}
}
This still isn't good code though:
Don't store plain-text passwords in a database
Handle the case where there are no results
Don't build your own authentication system at all; use an existing one written by people with more experience in securing data
I am using ASP.NET membership because this is not typical website to have that kind of authentication. I have table that Admin assigns with Uname and Password (Encrypted).
I have a LogIn page when clicked on Login button I need to search for the user in my DB table.
public void getuserinfo()
{
String var = System.Configuration.ConfigurationManager
.ConnectionStrings["KKSTechConnectionString"].ConnectionString;
SqlConnection conn = new SqlConnection(var);
SqlCommand myCmd = new SqlCommand("SELECT Username, Pass FROM Users", conn);
conn.Open();
if(TextBox1== Username) && (TextBox2== Password) <- I am not able to get this right :(
{
//How do I get his info??
}
}
*Database table for dbo.users:*
Uname(PK) | Pass | EmpID (FK)
I want to first decrypt the password and then compare it with the TextBoxPassword..
Please help.
Another approach will be to hash the password entered at user screen and compare that with the hashed password stored at the database.
Now, use your function like this.
public void ValidateUser()
{
var connectionString = System.Configuration.ConfigurationManager
.ConnectionStrings["KKSTechConnectionString"].ConnectionString;
var userName = txtUserName.Text;
var hashedPassword = Helper.ComputeHash(txtPassword.Text, "SHA512", null);
// this query should be parameterised when used in production to avoid SQL injection attacks
var query = String.Format("SELECT Username, Pass FROM Users WHERE Username='{0}' AND Pass='{1}'",
userName,
hashedPassword);
using(var connection = new SqlConnection( connectionString ))
using(var command = new SqlCommand(query, connection ))
{
conn.Open();
SqlDataReader reader=command.ExecuteReader();
if(reader.Read())
{
}
reader.Close();
}
}
Few questions before we get to solution:
How are you sending username and password from client to server side? Is it plain text?
Where does encryption happens?
Have you written encryption code or using one of the standards available?
In your code, I can notice following issues:
You have created the connection object and command object although you have never executed the query on the database.
The query you are using return entire user table which is definitely not required. You already have the user inputs for username and password so just find if they are correct.
Make your query parameterized and send the input to database. There, check if the username and password match. If they do, send back user details (which you will need somewhere in the application, I suppose) or else either, throw exception or return null.
Make sure to take care of encryption/decryption before matching username and password.
the underlying database on a project has changed from sql 2005 to MySql 5.1
The code has loads of method similar to below. I'm presuming it is just a case of switching the 'con' variable SqlConnection to a MYSql specific connection. Has anyone had any experience with this? I have never touched a mySql db. Any help much appreciated.
private SqlConnection con;
public User LogonUser(string pUserName, string pPassword)
{
con = new SqlConnection();
con.ConnectionString = DatabaseConstants.DB_CONN_STRING;
using (con)
{
con.Open();
var command = new SqlCommand();
command.Connection = con;
command.CommandText = "SELECT id FROM Users WHERE userName = #userName AND password = #password";
command.CommandType = CommandType.Text;
var userName = new SqlParameter("#userName", pUserName);
var password = new SqlParameter("#password", pPassword);
command.Parameters.Add(userName);
command.Parameters.Add(password);
User user;
var dr = command.ExecuteReader();
if (dr != null)
if (dr.HasRows)
{
while (dr.Read())
{
user = new User();
user.id = dr.GetString(0);
return user;
}
}
else
{
throw new Exception("Can not find user, please check your username and password");
}
}
return null;
}
You got it partially correct, but you will need an instance of the MySQL Provider, not the SqlConnection. Also you will have to change any SQL that isn't compatible with MySQL.
Downloadable SQL Connectors are available for various frameworks and platforms - in this case assemblies to reference into your .NET project under the guise of ADO.NET are available from MySql. Can program against them using any .NET language.
Start in C# by referencing the MySql namespace:
using MySql.Data.MySqlClient;
and change over your ADO.NET class names from SqlConnection to MySqlConnection, etc. Google Code examples show cursory usage (similar to other ADO.NET providers), and of course the MySql docs are the best reference.
No, you have to also change this line
var command = new SqlCommand();
to
var command = new con.CreateCommand();
and of course you have to change any specific T-SQL and MSSQL features to MySQL. Date and time function, stored procedure, and parameter binding(? instead of #) are a few things that you need to closely check.