To nie jest odpowiedź na NullReferenceException
- wciąż nad tym pracujemy w komentarzach; to jest informacja zwrotna dla części bezpieczeństwa.
Pierwszą rzeczą, na którą możemy się przyjrzeć, jest wstrzykiwanie SQL; jest to bardzo łatwe do naprawienia - patrz poniżej (pamiętaj, że uporządkowałem też kilka innych rzeczy)
// note: return could be "bool" or some kind of strongly-typed User object
// but I'm not going to change that here
public string[] GetValidUser(string dbUsername, string dbPassword)
{
// no need for the table to be a parameter; the other two should
// be treated as SQL parameters
string query = @"
SELECT id,email,password FROM tbl_user
WHERE [email protected] AND [email protected]";
string[] resultArray = new string[3];
// note: it isn't clear what you expect to happen if the connection
// doesn't open...
if (this.OpenConnection())
{
try // try+finally ensures that we always close what we open
{
using(MySqlCommand cmd = new MySqlCommand(query, connection))
{
cmd.Parameters.AddWithValue("email", dbUserName);
// I'll talk about this one later...
cmd.Parameters.AddWithValue("password", dbPassword);
using(MySqlDataReader dataReader = cmd.ExecuteReader())
{
if (dataReader.Read()) // no need for "while"
// since only 1 row expected
{
// it would be nice to replace this with some kind of User
// object with named properties to return, but...
resultArray[0] = dataReader.GetInt32(0).ToString();
resultArray[1] = dataReader.GetString(1);
resultArray[2] = dataReader.GetString(2);
if(dataReader.Read())
{ // that smells of trouble!
throw new InvalidOperationException(
"Unexpected duplicate user record!");
}
}
}
}
}
finally
{
this.CloseConnection();
}
}
return resultArray;
}
Teraz możesz pomyśleć „to za dużo kodu” – jasne; i istnieją narzędzia, które w tym pomagają! Załóżmy na przykład, że zrobiliśmy:
public class User {
public int Id {get;set;}
public string Email {get;set;}
public string Password {get;set;} // I'll talk about this later
}
Następnie możemy użyć dapper i LINQ, aby wykonać za nas wszystkie ciężkie prace:
public User GetValidUser(string email, string password) {
return connection.Query<User>(@"
SELECT id,email,password FROM tbl_user
WHERE [email protected] AND [email protected]",
new {email, password} // the parameters - names are implicit
).SingleOrDefault();
}
To robi wszystko masz (w tym bezpieczne otwieranie i zamykanie połączenia), ale robi to czysto i bezpiecznie. Jeśli it metoda zwraca null
wartość dla User
, oznacza to, że nie znaleziono dopasowania. Jeśli niepusty User
zwracana jest instancja - powinna zawierać wszystkie oczekiwane wartości, używając konwencji opartych na nazwach (co oznacza:nazwy właściwości i nazwy kolumn są zgodne).
Możesz zauważyć, że jedyny kod, który pozostaje, to właściwie przydatny kod - to nie jest nudna hydraulika. Narzędzia takie jak elegancki są twoim przyjacielem; użyj ich.
Wreszcie; Hasła. Nigdy nie należy przechowywać haseł. Kiedykolwiek. Ani razu. Nawet nie zaszyfrowane. Nigdy. Powinieneś tylko przechowuj hasze haseł. Oznacza to, że nigdy nie możesz ich odzyskać. Zamiast tego należy haszować to, co dostarcza użytkownik i porównać to z wcześniej istniejącą wartością haszowaną; jeśli hashe pasują:to jest pass. Jest to skomplikowany obszar i będzie wymagał znaczących zmian, ale należy to zrobić . To jest ważne. To, co masz w tej chwili, jest niepewne.