Login per Datenbank gibt Fehlermeldung (1054) zurück.

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Hart mit Bart
User
Beiträge: 25
Registriert: Dienstag 30. Oktober 2018, 12:05

Hallöchen,
ich möchte einen eigentlich simplen Login erstellen. Aber irgendwie stelle ich mich dabei doof an. *Kopf kratz*

Das ist das Script:

Code: Alles auswählen

import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button

from getpass import getpass
import mysql.connector


class MyGridLayout(GridLayout):
    # Initialize infinite keywords
    def __init__(self, **kwargs):
        # Call grid layout constructor
        super(MyGridLayout, self).__init__(**kwargs)

        # Set columns
        self.cols = 1

        # Create 2nd grid layout
        self.top_grid = GridLayout()
        self.top_grid.cols = 2

        # Add widgets
        self.top_grid.add_widget(Label(text="Benutzer: "))
        # Add Input Box
        self.name = TextInput(multiline=False)
        self.top_grid.add_widget(self.name)

        self.top_grid.add_widget(Label(text="Passwort: "))
        # Add Input Box
        self.password = TextInput(multiline=False)
        self.top_grid.add_widget(self.password)

        # Add the new top_grid to app
        self.add_widget(self.top_grid)

        # Create a submit button
        self.submit = Button(text="Einloggen", font_size=32)
        # Bind button
        self.submit.bind(on_press=self.press)
        self.add_widget(self.submit)

    def press(self, instance):
        # Create or connect to DB

        # Define DB
        mydb = mysql.connector.connect(
            host="localhost",
            user="root",
            passwd="passwort",
            database="quiz"
        )

        # Create a cursor
        c = mydb.cursor()

        # Get data from DB
        c.execute(f"SELECT superuser FROM users WHERE username={self.name.text} AND password={self.password.text}")
        result = c.fetchall()


class MyApp(App):
    def build(self):
        return MyGridLayout()

if __name__ == "__main__":
    MyApp().run()
Es erscheint folgende Fehlermeldung:
mysql.connector.errors.ProgrammingError: 1054 (42S22): Unknown column 'Hans' in 'where clause'
Allerings gibt es den User in der Datenbank. Und wenn ich statt {self.name.text} direkt "Hans" (nebst entsprechendem Passwort) in die Abfrage schreibe, bekomme ich auch das erwartete Ergebnis (superuser) zurück.

Der Fehler liegt also beim {self.xxx.text}. Aber irgendwie finde ich nicht heraus, was da falsch läuft. Wenn ich das zur Prüfung per print-Befehl in die Konsole ausgeben lasse, steht da genau das, was ich erwarte.

Könnte mir jemand einen Schubs in die richtige Richtung geben?

Liebe Grüße.

System:
Win 10
PyCharm 2022.1.2 Community
XAMPP 3.3.0 (Apache, MySQL)
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hart mit Bart: Da steht nicht das was Du erwartest, ausser Du würdest den gleichen Fehler manuell auch machen. Da steht dann ``… WHERE username=Hans AND …`` was genau zu dem Fehler führt, weil es keine Spalte mit dem Namen `Hans` gibt.

Der grundsätzliche Fehler hier ist aber, dass man keine Werte in Zeichenketten mit SQL hinein formatiert, denn selbst wenn man es ”richtig” macht, ist das bestenfalls fragil, und im schlimmsten Fall, wenn die Eingaben direkt von einem Benutzer kommen, ein Sicherheitsproblem. In das erste Argument von `execute()` gehören Platzhalter für die Werte, und die Werte selbst werden als zweites Argument an `execute()` übergeben. Schau Dir die Beispiele in der Dokumentation an.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Hart mit Bart
User
Beiträge: 25
Registriert: Dienstag 30. Oktober 2018, 12:05

Ah, ich seh schon. Mir war zwar klar, dass ich das mit den Parametern versaubeutelt habe, aber nicht wie. Die Sache mit den Escape Strings hatte ich vorher schlicht nicht begriffen. Zwar habe ich das in Codebeispielen gesehen, aber den Sinn eben nicht verstanden. Ich dachte, dass das doch das Gleiche in grün sein müsse. War natürlich Blödsinn.

Code: Alles auswählen

data = (self.name.text, self.password.text)
        sql = """
            SELECT superuser 
            FROM users
            WHERE username = %s
            AND password = %s
        """
        c.execute(sql, data)
        result = c.fetchall()
Der Code funktioniert.

Übrigens ist das nur Spielerei bzw. ein Lernprojekt. Jemand anderes wird das kaum je ausführen. Aber ich behalte das mit der Sicherheit auf dem Schirm. Muss ich eh irgendwann auch lernen.

Edit: Dankeschön. :)
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Noch einige Anmerkungen zum Code:
`getpass` wird importiert, aber nicht benutzt (ist bei einer GUI auch wenig sinnvoll).
`My` ist eine wenig aussagekräftiges Präfix; nenne Klassen oder Variablen für was sie stehen.
`super` wird seit Python3 ohne Argumente benutzt.
Die Kommentare sind allesamt überflüssig, weil sie nur das beschreiben, was in der nächsten Zeile eh steht.
Sowohl die Datenbankverbindung als auch der Cursor müssen mit `close` auch wieder geschlossen werden. Es ist zu erwarten, dass die Datenbank garantiert, dass es nur einen Nutzer mit dem angegebenen Namen gibt, so dass fetchone besser ist als fetchall. `result` wird gar nicht verwendet.
Hart mit Bart
User
Beiträge: 25
Registriert: Dienstag 30. Oktober 2018, 12:05

Teilweise kommt das noch von den Tutorials, die ich durchgearbeitet habe. Zumindest die Sache mit den Kommentaren finde ich nicht völlig sinnlos aus der Perspektive eines Anfängers. Wenn ich das eintippe, brennt sich mir das eher ein. Später werde ich das aber bestimmt aufgeräumter gestalten.

@"super"
Habe das gerade mal nachgelesen auf python.org. Wieder etwas Code gespart.
Es ist zu erwarten, dass die Datenbank garantiert, dass es nur einen Nutzer mit dem angegebenen Namen gibt, so dass fetchone besser ist als fetchall. `result` wird gar nicht verwendet.
Genau. Es gibt nur einen User, der in der Datenbank bei "superuser" den Wert 1 hat. Alle anderen haben den Wert 0.
Das "result" stand noch im Code, weil ich da mit "print" geschaut habe, ob und was ich da überhaupt zurück bekomme.

Danke für die Hinweise.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Hart mit Bart: Es geht nicht darum bei wie vielen Datensätzen `superuser` den Wert 1 hat, sondern dass Benutzernamen ja hoffentlich eindeutig sind und es nicht mehrere Benutzer mit dem gleichen Benutzernamen gibt. Also das `username` in der Tabelle als ``NOT NULL`` und ``UNIQUE`` angelegt wurde.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten