Eigenes Forum mit FastAPI erstellen: Schritt 7 - Berechtigungen
James Reed
Infrastructure Engineer · Leapcell

Im vorherigen Artikel haben wir Kommentare und Antworten für unser Forum implementiert, was die Interaktion in der Community erheblich verbessert hat.
Interaktion kann jedoch zwangsläufig zu Konflikten führen. Mit zunehmender Interaktion wird Community-Management zu einem Problem, dem wir uns stellen müssen. Was, wenn jemand bösartige Inhalte postet?
In diesem Artikel führen wir ein grundlegendes Berechtigungsmanagementsystem ein. Wir werden eine „Admin“-Rolle einrichten und Administratoren die Möglichkeit geben, Benutzer zu „sperren“, um die Community-Ordnung aufrechtzuerhalten.
Schritt 1: Das Datenbankmodell aktualisieren
Wir müssen zwei Felder zur Benutzertabelle (users) hinzufügen: eines, um zu identifizieren, wer ein Admin ist, und ein weiteres, um zu markieren, wer „gesperrt“ wurde.
Öffnen Sie models.py und ändern Sie das User-Modell:
models.py (Benutzermodell aktualisieren)
from sqlalchemy import Column, Integer, String, ForeignKey, Boolean from sqlalchemy.orm import relationship from database import Base class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True, index=True) username = Column(String, unique=True, index=True) hashed_password = Column(String) # --- Neue Felder --- is_admin = Column(Boolean, default=False) is_banned = Column(Boolean, default=False) # ----------------- posts = relationship("Post", back_populates="owner", cascade="all, delete-orphan") comments = relationship("Comment", back_populates="owner", cascade="all, delete-orphan") # ... Post- und Comment-Modelle bleiben unverändert ...
Wir haben zwei Felder hinzugefügt: is_admin und is_banned. Beide sind auf default=False gesetzt, um bestehende Benutzer nicht zu beeinträchtigen.
Nach der Aktualisierung des Modells müssen Sie Ihre Datenbanktabellenstruktur manuell aktualisieren. Die entsprechenden SQL-Anweisungen lauten wie folgt:
-- Fügt die Spalte is_admin zur Tabelle users hinzu ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT FALSE; -- Fügt die Spalte is_banned zur Tabelle users hinzu ALTER TABLE users ADD COLUMN is_banned BOOLEAN DEFAULT FALSE;
Wenn Ihre Datenbank mit Leapcell erstellt wurde,
können Sie diese SQL-Anweisungen direkt in seinem webbasierten Bedienfeld ausführen.

Schritt 2: Manuell einen Administrator ernennen
Unser Forum verfügt noch nicht über ein „Admin-Backend“, um Administratoren zu ernennen. Da die Erstellung eines Admins eine seltene Anforderung ist, können wir die Datenbank direkt bearbeiten, um Ihren Benutzer manuell als Admin festzulegen.
Führen Sie den folgenden Befehl in Ihrer Datenbank aus:
-- Setzt den Benutzer mit dem Benutzernamen 'your_username' als Administrator UPDATE users SET is_admin = TRUE WHERE username = 'your_username';
Denken Sie daran, your_username durch den von Ihnen registrierten Benutzernamen zu ersetzen.
Schritt 3: Die Admin-Panel-Seite erstellen
Wir benötigen eine Seite, die nur Administratoren zugänglich ist und alle Benutzer anzeigt sowie Aktionsschaltflächen bereitstellt.
Erstellen Sie im Ordner templates eine neue Datei namens admin.html.
templates/admin.html
<!DOCTYPE html> <html> <head> <title>Admin Panel - My FastAPI Forum</title> <style> body { font-family: sans-serif; margin: 2em; } li { margin-bottom: 10px; } button { margin-left: 10px; padding: 5px; } </style> </head> <body> <h1>Admin Panel - User Management</h1> <a href="/posts">Back to Home</a> <hr /> <ul> {% for user in users %} <li> <strong>{{ user.username }}</strong> <span>(Admin: {{ user.is_admin }}, Banned: {{ user.is_banned }})</span> {% if not user.is_admin %} {% if user.is_banned %} <form action="/admin/unban/{{ user.id }}" method="post" style="display: inline;"> <button type="submit" style="background-color: #28a745; color: white;">Unban</button> </form> {% else %} <form action="/admin/ban/{{ user.id }}" method="post" style="display: inline;"> <button type="submit" style="background-color: #dc3545; color: white;">Ban</button> </form> {% endif %} {% endif %} </li> {% endfor %} </ul> </body> </html>
Diese Seite durchläuft alle Benutzer. Wenn ein Benutzer kein Admin ist, wird daneben eine Schaltfläche „Sperren“ oder „Entsperren“ angezeigt. Diese Schaltflächen verweisen über eine POST-Anfrage auf die Routen, die wir gerade erstellen werden.
Schritt 4: Die Admin-Backend-Routen erstellen
Nun müssen wir neue Routen in main.py hinzufügen, um die Admin-Panel-Logik zu verarbeiten.
main.py (Neue Routen und Abhängigkeit hinzufügen)
# ... (Vorherige Importe bleiben unverändert) ... # --- Abhängigkeiten --- # ... (get_current_user bleibt unverändert) ... # 1. Eine neue Abhängigkeit hinzufügen, um Admin-Berechtigungen zu überprüfen async def get_admin_user( current_user: Optional[models.User] = Depends(get_current_user) ) -> models.User: if not current_user: raise HTTPException( status_code=status.HTTP_302_FOUND, detail="Not authenticated", headers={"Location": "/login"} ) if not current_user.is_admin: # Wenn kein Admin, wird ein 403-Fehler ausgelöst raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="You do not have permission to access this resource." ) return current_user # --- Routen --- # ... (Vorherige Routen /, /posts, /api/posts usw. bleiben unverändert) ... # 2. Admin-Panel-Route hinzufügen @app.get("/admin", response_class=HTMLResponse) async def view_admin_panel( request: Request, db: AsyncSession = Depends(get_db), admin_user: models.User = Depends(get_admin_user) ): # Alle Benutzer abfragen result = await db.execute(select(models.User).order_by(models.User.id)) users = result.scalars().all() return templates.TemplateResponse("admin.html", { "request": request, "users": users }) # 3. Benutzer sperren-Route @app.post("/admin/ban/{user_id}") async def ban_user( user_id: int, db: AsyncSession = Depends(get_db), admin_user: models.User = Depends(get_admin_user) ): result = await db.execute(select(models.User).where(models.User.id == user_id)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="User not found") # Admins können keine anderen Admins sperren if user.is_admin: raise HTTPException(status_code=403, detail="Cannot ban an admin") user.is_banned = True await db.commit() return RedirectResponse(url="/admin", status_code=status.HTTP_303_SEE_OTHER) # 4. Benutzer entsperren-Route @app.post("/admin/unban/{user_id}") async def unban_user( user_id: int, db: AsyncSession = Depends(get_db), admin_user: models.User = Depends(get_admin_user) ): result = await db.execute(select(models.User).where(models.User.id == user_id)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="User not found") user.is_banned = False await db.commit() return RedirectResponse(url="/admin", status_code=status.HTTP_303_SEE_OTHER) # ... (Nachfolgende Routen /posts/{post_id}, /posts/{post_id}/comments usw. bleiben unverändert) ...
Dies beinhaltet die folgenden Hauptänderungen:
- Erstellung einer neuen Abhängigkeit
get_admin_user, die aufget_current_userbasiert und zusätzlich prüft, obcurrent_user.is_adminTrueist. - Erstellung der Route
GET /admin, die alle Benutzer abfragt und die Vorlageadmin.htmlrendert. Diese Route ist durchDepends(get_admin_user)geschützt, um sicherzustellen, dass nur Admins darauf zugreifen können. - Erstellung der Routen
POST /admin/ban/{user_id}undPOST /admin/unban/{user_id}zum Sperren/Entsperren spezifischer Benutzer.
Schritt 5: Die Sperre durchsetzen (Beiträge verhindern)
Ein Benutzer kann jetzt als „gesperrt“ markiert werden, aber seine Aktionen haben noch keine Auswirkung. Ein gesperrter Benutzer kann immer noch Beiträge und Kommentare erstellen.
Wir müssen die Routen create_post und create_comment ändern, um den Status des Benutzers zu überprüfen, bevor die Aktion ausgeführt wird.
main.py (Update create_post und create_comment)
# ... (Vorheriger Code) @app.post("/api/posts") async def create_post( title: str = Form(...), content: str = Form(...), db: AsyncSession = Depends(get_db), current_user: Optional[models.User] = Depends(get_current_user) ): if not current_user: return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND) # --- Prüfung hinzufügen --- if current_user.is_banned: raise HTTPException(status_code=403, detail="You are banned and cannot create posts.") # --------------- new_post = models.Post(title=title, content=content, owner_id=current_user.id) # ... (Nachfolgender Code bleibt unverändert) ... db.add(new_post) await db.commit() await db.refresh(new_post) return RedirectResponse(url="/posts", status_code=status.HTTP_303_SEE_OTHER) # ... (Andere Routen) @app.post("/posts/{post_id}/comments") async def create_comment( post_id: int, content: str = Form(...), parent_id: Optional[int] = Form(None), db: AsyncSession = Depends(get_db), current_user: Optional[models.User] = Depends(get_current_user) ): if not current_user: return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND) # --- Prüfung hinzufügen --- if current_user.is_banned: raise HTTPException(status_code=403, detail="You are banned and cannot create comments.") # --------------- new_comment = models.Comment( content=content, post_id=post_id, owner_id=current_user.id, parent_id=parent_id ) # ... (Nachfolgender Code bleibt unverändert) ... db.add(new_comment) await db.commit() return RedirectResponse(url=f"/posts/{post_id}", status_code=status.HTTP_303_SEE_OTHER) # ... (Nachfolgende Routen /posts/{post_id}/edit, /register, /login, /logout usw. bleiben unverändert) ...
Wenn jetzt ein gesperrter Benutzer versucht, ein Beitrags- oder Kommentarformular zu senden, lehnt das Backend die Anfrage ab und gibt einen 403-Fehler zurück.
Schritt 6: Die Frontend-Benutzeroberfläche aktualisieren
Das Backend ist jetzt sicher, aber aus Sicht der Benutzererfahrung sollten wir die Formulare für Beiträge und Kommentare vom Frontend ausblenden und Administratoren einen Einstiegspunkt zum Backend geben.
templates/posts.html (Update)
... (Kopfzeile und Stile bleiben unverändert) ... <body> <header> <h1>Welcome to My Forum</h1> <div class="auth-links"> {% if current_user %} <span>Welcome, {{ current_user.username }}!</span> {% if current_user.is_admin %} <a href="/admin" style="color: red; font-weight: bold;">[Admin Panel]</a> {% endif %} <a href="/logout">Logout</a> {% else %} <a href="/login">Login</a> | <a href="/register">Register</a> {% endif %} </div> </header> {% if current_user and not current_user.is_banned %} <h2>Create a New Post</h2> <form action="/api/posts" method="post"> <input type="text" name="title" placeholder="Post Title" required /><br /> <textarea name="content" rows="4" placeholder="Post Content" required></textarea><br /> <button type="submit">Post</button> </form> {% elif current_user and current_user.is_banned %} <p style="color: red; font-weight: bold;">You have been banned and cannot create new posts.</p> {% else %} <p><a href="/login">Login</a> to create a new post.</p> {% endif %} <hr /> ... (Beitragsliste bleibt unverändert) ... </body> </html>
templates/post_detail.html (Update)
... (Kopfzeile und Stile bleiben unverändert) ... <body> ... (Post-Detail-Abschnitt bleibt unverändert) ... <hr /> <div class="comment-form"> <h3>Post a Comment</h3> {% if current_user and not current_user.is_banned %} <form action="/posts/{{ post.id }}/comments" method="post"> <textarea name="content" rows="4" style="width:100%;" placeholder="Write your comment..." required></textarea><br /> <button type="submit">Submit</button> </form> {% elif current_user and current_user.is_banned %} <p style="color: red; font-weight: bold;">You have been banned and cannot post comments.</p> {% else %} <p><a href="/login">Log in</a> to post a comment.</p> {% endif %} </div> ... (Kommentarabschnitt bleibt unverändert) ... </body> </html>
Dies beinhaltet zwei Hauptänderungen:
- In der Kopfzeile von
posts.htmlwird ein Link zum „Admin Panel“ angezeigt, wenn der aktuelle Benutzer ein Admin ist (current_user.is_admin). - In
posts.htmlundpost_detail.htmlwird die ursprüngliche Bedingung{% if current_user %}in{% if current_user and not current_user.is_banned %}geändert. Das bedeutet, dass nur Benutzer, die nicht gesperrt sind, das Formular sehen können.
Ausführen und Überprüfen
Starten Sie Ihren uvicorn-Server neu:
uvicorn main:app --reload
Melden Sie sich bei Ihrem Admin-Konto an. Sie sollten den Link „Admin Panel“ oben rechts sehen.

Klicken Sie darauf, um zur /admin-Seite zu gelangen. Sie sehen eine Liste aller Benutzer und können andere Benutzer sperren.

Sperren Sie test_user. Wechseln Sie zur Anmeldung als test_user, und Sie werden feststellen, dass das Formular „Create New Post“ verschwunden ist und durch die Meldung „You have been banned“ ersetzt wurde.

Fazit
Wir haben grundlegende Verwaltungsfunktionen zum Forum hinzugefügt. Mithilfe der Felder is_admin und is_banned haben wir die Benutzerrollendifferenzierung und die Berechtigungskontrolle unterstützt.
Basierend auf diesem Framework können Sie weitere Verwaltungsfunktionen erweitern, wie z. B. Benutzer per Schatten sperren oder Anmeldungen verbieten.
Mit wachsendem Inhalt des Forums wird es für Benutzer schwierig, alte Beiträge, an denen sie interessiert sind, zu finden.
Um dies zu beheben, werden wir im nächsten Artikel eine Suchfunktion zum Forum hinzufügen.

