Hallo!
Habe ein Problem bei einem Passwortabgleich zwischen einer Mysql-DB und einem C# Prog.. Ich schreibe gerade ein Programm. Bei dem sich ein Benutzer mit Benutzernamen und Kennwort anmelden kann. Die Benutzernamen und Kennwörter sind in einer Mysql-Datenbank abgelegt. Ich habe hier auf MyCsharp schon einige Threads zu diesem Thema gefunden und auch eine anscheinend gute Lösung. Nur klappt diese nicht so ganz bei mir. Ich finde aber den Fehler nicht. Denke mal das ist nur eine Kleinigkeit und ich stelle mich einfach nur zu dumm an. Hier der Quellcode zur Überprüfung des Benutzernamens und des Kennwortes. Wenn ich Debugge, bekomme ich zwei Fehler: Verwendung der nicht zugewiesenen lokalen Variablen "Benutzername" und die gleiche mit "Benutzerpasswort". Die Variablen habe ich aber eigentlich zugewiesen (Denke ich zumindest). Für mögliche Lösungsvorschläge und oder Beispiele bin ich sehr dankbar. Bin absoluter Neuling auf diesem Gebiet.
private void btnOK_Click(object sender, EventArgs e)
{
string str_username = tbBN.Text;
string str_Kennwort = tbPW.Text;
//Verbindung
string conStr = "server=localhost;uid=root;pwd=flippi;database=lager;Port=3306";
MySqlConnection MysqlConn = new MySqlConnection(conStr);
//Reader erzeugen
MySqlDataReader dbReader = null;
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = MysqlConn;
cmd.Parameters.Add("@Benutzername","benutzername");
cmd.Parameters.Add("@Benutzerpasswort","benutzerpasswort");
cmd.CommandText = "SELECT benutzername AS Benutzername, benutzerpasswort AS Benutzerpasswort FROM benutzer where benutzername = " + this.tbBN.Text +"";
try
{
MysqlConn.Open();
// str_benutzername = "benutzername".ToString();
dbReader = cmd.ExecuteReader();
string benutzername;
string benutzerpasswort;
while(dbReader.Read())
{
benutzername = (string)dbReader.GetValue(2);
benutzerpasswort = (string)dbReader.GetValue(3);//Spalte in tabelle
}
if (str_username == benutzername && str_Kennwort == benutzerpasswort)
{
MessageBox.Show("OK");
}
else
{
MessageBox.Show("Falsches Kennwort oder Benutzername");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
MysqlConn.Close();
}
//edit: C#-Code-Tags richtig gestellt!!!
Die Variablen habe ich aber eigentlich zugewiesen (Denke ich zumindest).
ja, die werden aber nur zugewiesen, wenn deine Schleife
while(dbReader.Read())
{
benutzername = (string)dbReader.GetValue(2);
benutzerpasswort = (string)dbReader.GetValue(3);//Spalte in tabelle
}
auch durchlaufen wird, ansonsten nicht.
Ich vermute mal, das daher deine Fehlermeldung kommt!!
nils
Hi Nils!
Danke für die rasche Antwort. Kommt mir auch logisch vor, wie du es sagst... Aber wie helfe ich dem ab? Andere Schleife: do{} while?
Gruß Philipp
Hallo flippi,
cmd.CommandText = "SELECT benutzername AS Benutzername, benutzerpasswort AS Benutzerpasswort FROM benutzer where benutzername = " + this.tbBN.Text +"";
Was passiert eigentlich, wenn ich als Benutzer folgendes (oder schlimmeres) in die tbBN eintrage:
'Meier'; delete from benutzer;
Wenn Du schon Parameter zuweist, solltest Du diese auch benutzen....
while(reader.Read())....
Zuerst würde ich prüfen, ob überhaupt ein Datensatz gefunden wurde (
reader.HasRows()
Ich hoffe, dass in der Db die Tabelle benutzer einen unique-Constraint auf den benutzernamen hat; wenn nicht kann es passieren. dass Du zwei oder mehr Datensätze zurück bekommst -> welcher Benutzer soll denn angemeldet werden....
Grüße
Morpheus
Hallo Morpheus!
Dann wird der Benutzer Maier gelöscht, aber so weit will ich noch nicht denken. Es soll ersteinmal nur funktionieren. Oder hast du auf die Schnelle ein Beispiel parat? Aber wie gesagt, es soll sich erst einmal jemand anmelden können (egal ob mit Sicherheitsrisiko oder ohne). Wenns funzt, schau ich am Ende nach der Perfektion...
Gruß
flippi
Hallo Flippi,
statt
string benutzername;
string benutzerpasswort;
...
schreibe
string benutzername = "";
string benutzerpasswort = "";
...
Wenn Du Variablen verwendest müssen Sie auch vorher zu 100% definiert sein. Und das ist bei Dir nicht der Fall, wenn nämlich kein Datensatz gefunden wurde.
Grüße Bernd
Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3
Original von flippi
Dann wird der Benutzer Maier gelöscht, aber so weit will ich noch nicht denken. ... (egal ob mit Sicherheitsrisiko oder ohne). Wenns funzt, schau ich am Ende nach der Perfektion...
Hallo flippi,
das von mir genannte Problem löscht Dir nicht den Benutzer "Meier" sondern die gesamte Benutzertabelle! Das hat nichts mit Perfektion zu tun, sondern ist einfach nur fahrlässig.
aber zurück zum Thema:
Das gehashte Passwort befindet sich in der dritten Spalte. Das vom Benutzer eingegebene PW wird dieser Methode übergeben.
public bool CheckCredential(string username, string hashedPassphrase) {
using (DbCommand selectUser = factory.CreateCommand()) {
selectUser.CommandText = "SELECT * FROM USERDATA WHERE USERNAME=@username";
selectUser.Connection = connection;
DbParameter param = selectUser.CreateParameter();
param.DbType = DbType.String;
param.ParameterName = "@username";
param.Value = username;
selectUser.Parameters.Add(param);
connection.Open();
DbDataReader reader = selectUser.ExecuteReader();
if (reader.HasRows) {
if (reader.Read()) {
if (hashedPassphrase == reader.GetString(2)) {
return true;
}
}
}
return false;
}
Gruß
Morpheus
Hi Morpheus,
erstmal vielen Dank für deine Hilfe. Wenn ich dich richtig verstehe, sollte der Code bei mir dann so aussehen:
public bool CheckCredential(string username, string hashedPassphrase) {
using (DbCommand selectUser = factory.CreateCommand()) {
selectUser.CommandText = "SELECT * FROM benutzer WHERE Benutzername=@Benutzername";
selectUser.Connection = connection;
DbParameter param = selectUser.CreateParameter();
param.DbType = DbType.String;
param.ParameterName = "@Benutzername";
param.Value = username;
selectUser.Parameters.Add(param);
connection.Open();
DbDataReader reader = selectUser.ExecuteReader();
if (reader.HasRows) {
if (reader.Read()) {
if (hashedPassphrase == reader.GetString(2)) {
return true;
}
}
}
return false;
}
Aber wo füge ich den Code ein, dass es funzt? Danach hab ich ja trotzdem noch das Problemchen mit den zugewiesenen Variablen, oder.
Gruß Flippi
//Edit: C# code-tags ergänzt!! (bitte auf das Ende-Tag achten!)
Hallo flippi,
das mit den Variablen hat ja schon BerndFfm geschrieben.
Die Methode CheckCredentials ist, wie der Name schon sagt eine Methode....
...
if (CheckCredential(str_username, str_Kennwort))
{
MessageBox.Show("OK");
}
else
{
MessageBox.Show("Falsches Kennwort oder Benutzername");
}
...
Gruß
Morpheus
Vielen vielen Dank an BerndFfm und Morpheus, ich muss jetzt leider erst einmal unterbrechen, ich versuche die von euch genannten Tipps in die Tat umzusetzen. Ich schreibe morgen Vormittag wieder. Hoffe es funktioniert dann. Wünsche euch noch einen schönen Abend.
Liebe Grüße
Flippi
Hallo!
Hab da noch paar Problemchen, wenn ich einen Namen bei Benutzername eingebe, erhalte ich immer die Fehlermeldung unknown column 'Name' in 'where clause', obwohl der Name in der Tabelle benutzer vorhanden ist. Jemand eine Ahnung, wie ich das beseitigen kann???
Danke Morpheus, bekomme aber die Funktion leider nicht zum Laufen.
Bekomme beim Debuggen folgende Fehlermeldungen
Fehler 1 Der Name "Factory" ist im aktuellen Kontext nicht vorhanden. C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Visual Studio 2005\Projects\test1vdb\test1vdb\Form1.cs 88 47 test1vdb
Fehler 2 "MySql.Data.MySqlClient.MySqlConnection" ist ein(e) "Typ", wird aber wie ein(e) "Variable" verwendet. C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Visual Studio 2005\Projects\test1vdb\test1vdb\Form1.cs 91 41 test1vdb
Fehler 3 Für das nicht statische Feld, die Methode oder die Eigenschaft "System.Data.Common.DbConnection.Open()" ist ein Objektverweis erforderlich. C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Visual Studio 2005\Projects\test1vdb\test1vdb\Form1.cs 97 17 test1vdb
Hab deine Funktion folgendermaßen umgeschrieben:
public bool CheckCredential(string username, string hashedPassphrase)
{
using (MySqlCommand selectUser = Factory.CreateCommand())
{
selectUser.CommandText = "SELECT * FROM benutzer WHERE Benutzername=@Benutzername";
selectUser.Connection = MySqlConnection;
MySqlParameter param = selectUser.CreateParameter();
param.DbType = DbType.String;
param.ParameterName = "@Benutzername";
param.Value = username;
selectUser.Parameters.Add(param);
MySqlConnection.Open();
MySqlDataReader reader = selectUser.ExecuteReader();
if (reader.HasRows)
{
if (reader.Read())
{
if (hashedPassphrase == reader.GetString(2))
{
return true;
}
}
}
return false;
}
}
Den Namen Factory gibt es bei mir nicht, es gibt nur MySqlClientFactory und da nur Equals, Instance und ReferenceEquals.
Danke im Voraus für alle Antworten.
Gruß Flippi
//edit: C# Code TAgs richtig gestellt!! (Bitte auf das Ende-Tag achten!!!)
Hallo Flippi,
das mit dem Factory brauchst Du nur, wenn Du dein Programm mit verschiedenen Datenbanksystem betreiben willst (und nicht mal dann 😉 )
Wenn Dein Programm (erstmal) nur mit MySQL laufen soll dann nimm Deinen Code vom ersten Posting.
Wenn doch DBFactory musst Du "using System.Data.Common" einbinden und MySQL muss als DataBaseprovider eingetragen sein (app.conf oder so). Das sollte der mySQL Treiber aber automatisch machen bei der Installation.
Der Code sieht dann so aus :
DbConnection conn = null;
DbProviderFactory factory;
factory = DbProviderFactories.GetFactory("MySql.Data.MySqlClient");
conn = factory.CreateConnection();
" ... ist ein(e) "Typ", wird aber wie ein(e) "Variable" verwendet" : Dann hast Du meistens Klammern vergessen oder zuviele hingeschrieben.
Grüße Bernd
Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3
Hi BerndFfm!
Aber Morpheus hat ja gemeint, dass es fahrlässig ist, wenn ich nur den ersten Code benutze, da man beim eintippen des Users ja ein SQL-Kommando mit schreiben könnte und so die ganze Tabelle gelöscht würde (so hab ich ihn zumindest verstanden). Die Anwendung soll und muss nur auf einer MySql-Datenbank laufen.
Meinst du also, ich sollte die komplette Funktion (CheckCredential) nicht verwenden?
Aber auch wenn ich sie nicht verwende, das Problem mit der Abfrage besteht dennoch. Ich habe den Fehler schon im Internet gesucht, da steht, dass man die Select...Where...Clausel in eine Join...Clausel umwandeln soll, nur weiss ich nicht genau wie. Weist du das evtl.?
Bis jetzt sieht sie so aus:
cmd.CommandText = "SELECT benutzername AS Benutzername, benutzerpasswort AS Benutzerpasswort FROM benutzer WHERE benutzername = " + this.tbBN.Text + "";
[/csharp]
Aber Morpheus hat ja gemeint, dass es fahrlässig ist, wenn ich nur den ersten Code benutze, da man beim eintippen des Users ja ein SQL-Kommando mit schreiben könnte und so die ganze Tabelle gelöscht würde (so hab ich ihn zumindest verstanden).
damit meint er SQL-Injection --> bitte bei wikipedida nachschlagen, da eine Diskussion darüber hier nicht weiterhilft. Danke!
nils
Alles klar Nils!
Habs gerade nachgeschlagen. Danke für den Hinweis.
Dennoch bleibt mein Problem offen.
Gruß
Flippi
Nimm doch erstmal deinen zuerst geposteteten Code und ändere ihn wie ich vorgeschlagen habe. SQL-Injection kannst Du ja später verhindern.
Statt
if (reader.HasRows) { if (reader.Read()) {
reicht
if (reader.Read()) {
oder
while (reader.Read()) {
Grüße Bernd
Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3
Jo, Danke Bernd!
Das klappt, aber der String zur SQL-Datenbank nicht. Hast du da auch ne Idee?
Grüße
Philipp
😁
Wunderbar!
Das mit der Fehlermeldung hat funktioniert, hab den String für die Datenbank abgeänder in ...like'"...'"
und der Index vom DataReader war auch falsch (von 2 auf 0 und von 3 auf 1)
Danke
Grüße
Philipp