Teil 27: Benutzerkonten & Login – Aufgaben pro Nutzer


🎯 Ziel dieses Teils

✅ Nutzer können sich anmelden
✅ Jede Aufgabe gehört zu genau einem Benutzer
✅ Beim Login werden nur eigene Aufgaben angezeigt
✅ Logout möglich


Neue Tools

  • sqlite3: Unsere Datenbank – jetzt mit zwei Tabellen
  • Flask.session: Speichert, welcher Nutzer eingeloggt ist
  • werkzeug.security: Passwörter sicher speichern (mit Hash)

Struktur bleibt gleich

Du brauchst keine neuen Ordner – nur neue Tabellen und ein paar Templates.


Schritt 1: Neue Datenbankstruktur

init_db.py erweitern:

import sqlite3

connection = sqlite3.connect("db.sqlite")

with connection:
    connection.execute("""
        CREATE TABLE IF NOT EXISTS benutzer (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL UNIQUE,
            passwort TEXT NOT NULL
        );
    """)

    connection.execute("""
        CREATE TABLE IF NOT EXISTS aufgaben (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            text TEXT NOT NULL,
            erledigt INTEGER NOT NULL DEFAULT 0,
            benutzer_id INTEGER NOT NULL,
            FOREIGN KEY (benutzer_id) REFERENCES benutzer(id)
        );
    """)

print("📩 Datenbank aktualisiert.")

Dann im Terminal:

python init_db.py

Schritt 2: Login-Funktion vorbereiten

In app.py ganz oben:

from flask import Flask, render_template, request, redirect, url_for, session
from werkzeug.security import generate_password_hash, check_password_hash

app.secret_key = "ein_geheimer_schluessel"  # Ă€ndere das fĂŒr echte Apps!

Schritt 3: Registrierung & Login-Routen

Registrierung:

@app.route("/register", methods=["GET", "POST"])
def register():
    if request.method == "POST":
        name = request.form.get("name")
        pw = request.form.get("passwort")
        db = get_db()
        try:
            db.execute(
                "INSERT INTO benutzer (name, passwort) VALUES (?, ?)",
                (name, generate_password_hash(pw))
            )
            db.commit()
            return redirect(url_for("login"))
        except sqlite3.IntegrityError:
            return "Name bereits vergeben"
    return render_template("register.html")

Login:

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        name = request.form.get("name")
        pw = request.form.get("passwort")
        db = get_db()
        user = db.execute(
            "SELECT * FROM benutzer WHERE name = ?",
            (name,)
        ).fetchone()

        if user and check_password_hash(user["passwort"], pw):
            session["user_id"] = user["id"]
            session["name"] = user["name"]
            return redirect(url_for("startseite"))
        else:
            return "Login fehlgeschlagen"

    return render_template("login.html")

Logout:

@app.route("/logout")
def logout():
    session.clear()
    return redirect(url_for("login"))

Schritt 4: Nur angemeldete Benutzer zulassen

Am Anfang von startseite():

@app.route("/")
def startseite():
    if "user_id" not in session:
        return redirect(url_for("login"))

    db = get_db()
    user_id = session["user_id"]

    aufgaben = db.execute(
        "SELECT id, text, erledigt FROM aufgaben WHERE benutzer_id = ?",
        (user_id,)
    ).fetchall()

    aufgaben = [
        {"id": a["id"], "text": a["text"], "erledigt": bool(a["erledigt"])}
        for a in aufgaben
    ]
    
    ...

Ebenso bei allen anderen Funktionen (hinzufĂŒgen, löschen etc.) musst du benutzer_id = ? verwenden – du kannst gern sagen, wenn ich dir das ĂŒberall einsetzen soll (Teil 28?).


Schritt 5: Neue Templates

templates/login.html

<h1>🔐 Login</h1>
<form method="post">
    <input name="name" placeholder="Benutzername">
    <input name="passwort" type="password" placeholder="Passwort">
    <button type="submit">Einloggen</button>
</form>
<p>Noch keinen Account? <a href="/register">Registrieren</a></p>

templates/register.html

<h1>🆕 Registrierung</h1>
<form method="post">
    <input name="name" placeholder="Benutzername">
    <input name="passwort" type="password" placeholder="Passwort">
    <button type="submit">Registrieren</button>
</form>
<p>Schon einen Account? <a href="/login">Login</a></p>

Schritt 6: Aufgaben speichern mit Benutzer-ID

Beispiel: /hinzufuegen anpassen:

@app.route("/hinzufuegen", methods=["POST"])
def aufgabe_hinzufuegen():
    if "user_id" not in session:
        return redirect(url_for("login"))

    text = request.form.get("text")
    if text:
        db = get_db()
        db.execute(
            "INSERT INTO aufgaben (text, benutzer_id) VALUES (?, ?)",
            (text.strip(), session["user_id"])
        )
        db.commit()
    return redirect(url_for("startseite"))

Gleiches gilt fĂŒr löschen, erledigen, zurĂŒcksetzen, bearbeiten
→ dort immer: WHERE id = ? AND benutzer_id = ?
(sicherstellen, dass nur eigene Aufgaben verÀndert werden)


Ergebnis

  • Du kannst dich registrieren & einloggen
  • Jeder Benutzer hat seine eigenen Aufgaben
  • Nur eingeloggte Nutzer dĂŒrfen etwas tun
  • JSON ist Geschichte – SQLite ĂŒbernimmt alles sauber und sicher

Was du gelernt hast

KonzeptTechnik
Benutzer speichernTabelle benutzer mit Hash
Login-Sessionsession["user_id"] in Flask
Zugriff absichernWHERE benutzer_id = ?
Passwort-Hashingwerkzeug.security

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert