Bei SQLAlchemy (flask) Datenbank Tabelle Account überprüfen?


09.06.2023, 03:33

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.