Teil 28: Sicherheit & Zugriffskontrolle für mehrere Benutzer


🎯 Ziel dieses Teils

✅ Benutzer dürfen nur ihre eigenen Aufgaben sehen und ändern
✅ Alle Aktionen sind durch Benutzer-ID abgesichert
✅ Es gibt Rückmeldungen bei Fehlversuchen
✅ Im Interface steht, wer gerade eingeloggt ist


Was ist das Problem?

Aktuell nutzt du URLs wie:

/bearbeiten/5
/loeschen/7

Aber:
Ein Benutzer könnte manuell eine andere ID eintippen
(z. B. /loeschen/1 – und damit fremde Daten löschen!)

➡️ Lösung: Immer mit Benutzer-ID absichern!


Schritt 1: Zugriff auf eigene Aufgaben beschränken

Beispiel: /loeschen/<id>

Vorher:

@app.route("/loeschen/<int:id>")
def aufgabe_loeschen(id):
    db = get_db()
    db.execute("DELETE FROM aufgaben WHERE id = ?", (id,))
    db.commit()
    return redirect(url_for("startseite"))

Jetzt:

@app.route("/loeschen/<int:id>")
def aufgabe_loeschen(id):
    if "user_id" not in session:
        return redirect(url_for("login"))

    db = get_db()
    db.execute(
        "DELETE FROM aufgaben WHERE id = ? AND benutzer_id = ?",
        (id, session["user_id"])
    )
    db.commit()
    return redirect(url_for("startseite"))

🔐 Nur Aufgaben löschen, die dem eingeloggten Benutzer gehören


Schritt 2: Das gleiche Prinzip bei allen Aktionen

  • /erledigt/<id>
  • /zuruecksetzen/<id>
  • /bearbeiten/<id>
  • /bearbeiten/<id> [POST]

Immer:

WHERE id = ? AND benutzer_id = ?

Schritt 3: Fehlermeldung bei unerlaubtem Zugriff

Beispiel:

@app.route("/bearbeiten/<int:id>")
def aufgabe_bearbeiten(id):
    if "user_id" not in session:
        return redirect(url_for("login"))

    db = get_db()
    aufgabe = db.execute(
        "SELECT * FROM aufgaben WHERE id = ? AND benutzer_id = ?",
        (id, session["user_id"])
    ).fetchone()

    if aufgabe is None:
        return "❌ Zugriff verweigert", 403

    return render_template("bearbeiten.html", id=id, text=aufgabe["text"])

Du kannst hier später auch Flash-Meldungen oder eine eigene Fehlerseite einbauen.


Schritt 4: Aktuellen Benutzer im Template anzeigen

In deinen Templates kannst du prüfen, ob jemand eingeloggt ist:

{% if session.name %}
    <p>👤 Eingeloggt als: {{ session.name }} | <a href="/logout">Logout</a></p>
{% endif %}

Setze das am besten in den <body>-Bereich von index.html.


Schritt 5: Zugang zu geschützten Routen vereinheitlichen

Um dich nicht ständig zu wiederholen, kannst du eine kleine Hilfsfunktion bauen:

def login_erforderlich():
    if "user_id" not in session:
        return redirect(url_for("login"))

Dann überall am Anfang von geschützten Routen:

@app.route("/hinzufuegen", methods=["POST"])
def aufgabe_hinzufuegen():
    r = login_erforderlich()
    if r: return r

    ...

Optional kann man das später auch mit einem eigenen Decorator wie @login_required eleganter lösen.


Teste deine Sicherheit

  1. Logge dich als Benutzer A ein
  2. Erstelle Aufgabe → z. B. /bearbeiten/3
  3. Logge dich als Benutzer B ein
  4. Versuche, /bearbeiten/3 aufzurufen
    Zugriff verweigert!

Was du jetzt kannst

ThemaUmsetzung
Zugriff auf eigene DatenSQL mit benutzer_id = ?
Session anzeigen{{ session.name }} im Template
Zugriff absichernif "user_id" not in session
FehlerbehandlungRückgabe 403, eigene Nachricht

Bonus-Ideen

  • 💬 Flash-Nachrichten (Erfolg / Fehler)
  • 🔁 Weiterleitung zurück zur ursprünglichen Seite nach Login
  • 🚨 Logbuch: Wer hat was geändert?

Kommentare

Schreibe einen Kommentar

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