Toto není odpověď na NullReferenceException
- stále na tom pracujeme v komentářích; toto je zpětná vazba pro bezpečnostní části.
První věc, na kterou se můžeme podívat, je SQL injection; toto lze velmi snadno opravit – viz níže (všimněte si, že jsem upravil i některé další věci)
// 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;
}
Možná si teď říkáte „to je příliš mnoho kódu“ – jistě; a existují nástroje, které s tím pomohou! Předpokládejme například, že jsme udělali:
public class User {
public int Id {get;set;}
public string Email {get;set;}
public string Password {get;set;} // I'll talk about this later
}
Poté můžeme použít dapper a LINQ, aby za nás udělali veškerou těžkou práci:
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 dělá vše máte (včetně bezpečného otevírání a zavírání spojení), ale dělá to čistě a bezpečně. Pokud metoda vrací null
hodnotu pro User
, znamená to, že nebyla nalezena žádná shoda. Pokud User
nemá hodnotu null instance je vrácena – měla by obsahovat všechny očekávané hodnoty pouze pomocí konvencí založených na názvech (to znamená:názvy vlastností a názvy sloupců se shodují).
Možná si všimnete, že jediný kód, který zbývá, je skutečně užitečný kód - není to nudné instalatérství. Nástroje jako elegantní jsou vaším přítelem; použijte je.
Konečně; hesla. Nikdy byste neměli ukládat hesla. Vůbec. Ani jednou. Dokonce ani šifrované. Nikdy. Měli byste pouze uložit hash hesel. To znamená, že je nikdy nemůžete získat. Místo toho byste měli hašovat to, co uživatel dodává, a porovnat to s již existující hašovanou hodnotou; pokud se hash shoduje:to je povolení. Toto je komplikovaná oblast a bude vyžadovat značné změny, ale měli byste to udělat . Toto je důležité. To, co máte v tuto chvíli, není bezpečné.