Bei SQLAlchemy (flask) Datenbank Tabelle Account überprüfen?
Ich arbeite seit einiger Zeit mit Flask und SQLAlchemy und bin auf die Idee gekommen, eine Webapp für meine Schulklasse zu bauen. Dort soll man sich einloggen können, auf den (Untis-) Stundenplan schauen können usw..
Allerdings hab ich noch nie ein Login gebaut. (Mit Flask oder Django)
Ich habe eine Datenbank wo Nutzer registriert sind und Nutzername, Passwort sowie die IP Adresse des Computers wo er/sie sich das letzte mal angemeldet haben gespeichert.
Ich habe also nun eine Account Datenbank, eine Registrierungsfunktion, aber wie kann ich im Login programmieren dass er nach dem Benutzernamen sucht und das Passwort überprüft? Dazu habe ich auch nichts im Internet gefunden.
Code: Hier klicken(drive)
Ich weiß der Code ist nicht gerade der sicherste, aber da werden ja auch nicht Zahlungsdaten drauf gespeichert.
Danke im voraus, Lennart
Ich habe mal mich noch einmal im Internet über mein Problem beschäftigt und konnte mir folgenden Code snippet zusammenbauen:
def checkuser(username, password, ip):
user = db.users.filter_by(username=username, password=password).first()
#example for output
if user:
print('OK')
else:
print('Error')
Ich bekomme aber den Fehler: AttributeError: users. Muss ich da noch etwas importieren oder irgendwie eine Klasse erstellen?
1 Antwort
(...) eine Webapp für meine Schulklasse zu bauen (...)
Für ein Hobbyprojekt mag das eine nette Idee sein. Von einem Produktiveinsatz würde ich allerdings deutlich abraten, da offensichtlich Nutzerdaten verarbeitet werden müssen, für die du keinen Schutz garantieren kannst.
Ich habe eine Datenbank wo (...) Passwort (...) gespeichert (...)
Passwörter sollten definitiv nicht gespeichert werden. Generiere bei Registration stattdessen einen Hashwert (bspw. mit Flask-Bcrypt) und speichere den ab. Bei Login wird das gegebene Passwort ebenfalls gehasht und mit dem Hash aus der Datenbank verglichen.
(...) sowie die IP Adresse (...)
Die IP-Adresse stellt eine personenbezogene Information dar. Nutzer sollten also darüber informiert werden, dass eine Speicherung vorgenommen wird.
(...) aber wie kann ich im Login programmieren dass er nach dem Benutzernamen sucht und das Passwort überprüft?
Für den Login wäre es sinnvoll, die Extensions Flask-Login und Flask-WTF einzusetzen, denn die bringen einige nützliche Features mit.
Für das Loginformular bräuchtest du zunächst ein Model
class login_form(FlaskForm):
username = StringField(validators=[InputRequired()])
password = PasswordField(validators=[InputRequired()])
und eine Controller-Action, die zum einen das Formular ausliefert und zum anderen validiert, sollte sie via POST-Request aufgerufen worden sein.
@app.route("/login/", methods=("GET", "POST"), strict_slashes=False)
def login():
form = login_form()
if form.validate_on_submit():
try:
user = # search for user in database ...
if check_password_hash(user.password, form.password.data):
login_user(user)
return redirect(""" url for protected area ... """)
else:
# error handling ...
except Exception as ex:
# exception handling ...
return render_template("login.html", form=form)
Für Nutzer brauchst du noch eine Subklasse von UserMixin. Die kannst du zugleich mit der Datenbank verbinden (bzw. SQLAlchemy mappt die entsprechenden Felder dann automatisch).
from flask_login import UserMixin
import sqlalchemy as sa
class User(UserMixin, db.Model):
__tablename__ = "Name of your user database table ..."
id = sa.Column(sa.Integer, primary_key=True)
username = sa.Column(sa.String)
password = sa.Column(sa.String) # it is a hash value of course
Queries kannst du über das session-Objekt an die Datenbank feuern.
Beispiel:
user = session.execute(select(User).filter_by(username="...")).scalar_one()
Die check_password_hash-Funktion kommt von Flask-Bcrypt. Sie vergleicht zwei Hashes miteinander. Die login_user-Funktion wird von Flask-Login implementiert.
Die View zu guter Letzt ist nicht sonderlich spektakulär:
{% ... %}
<form method="POST">
{{ form.username(placeholder="Username") }}
{{ form.password(placeholder="Password") }}
{% etc. ... %}
<button>Login</button>
</form>
{% ... %}
All das ist soweit nur auf die wesentliche Grundfunktionalität fokussiert. Den Ausbau und eine weitere Einarbeitung überlasse ich dir.