Flask-Login — Benutzerregistrierung, Anmeldung, Abmeldung
In diesem Kapitel lernst du, die Benutzerauthentifizierung per Sitzung mit Flask-Login zu implementieren, die die wichtigste Sicherheitsmaßnahme in der Flask-Webentwicklung ist.
Was ist Flask-Login?
HTTP-Anfragen in Webanwendungen sind von Natur aus zustandslos — der Server merkt sich nicht automatisch, wer Sie sind.
Flask-LoginDurchSessionDer Mechanismus hält den Benutzerstatus aufrecht: Nach dem Login speichert der Server die Benutzer-ID in der Session, und nachfolgende Anfragen identifizieren automatisch den aktuellen Benutzer.
Installation und Initialisierung
(venv) $ pip install flask-login
Beispiel
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
app.config['SECRET_KEY'] = 'your-secret-key-here' # Session-Verschlüsselungsschlüssel (in Produktion Umgebungsvariable verwenden)
db = SQLAlchemy(app)
# LoginManager initialisieren
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'auth.login' # Nicht authentifizierte Benutzer zur Anmeldeseite umleiten
login_manager.login_message = 'Bitte melden Sie sich zuerst an, bevor Sie zugreifen.'
SECRET_KEYEs ist der Grundpfeiler des Flask-Sicherheitssystems — Session-Verschlüsselung, CSRF-Tokens und Flash-Nachrichten hängen alle davon ab. In Produktionsumgebungen muss es aus Umgebungsvariablen gelesen werden und darf nicht hartcodiert sein.
Das User-Modell definieren
Flask-Login erfordert, dass das User-ModellUserMixinmehrere bereitgestellte Methoden implementiert.
Beispiel
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
class User(UserMixin, db.Model):
"""Benutzermodell"""
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(256), nullable=False)
def set_password(self, password):
""" und verschlüsseln Sie das Passwort (niemals Klartextpasswörter speichern)"""
self.password_hash = generate_password_hash(password)
def check_password(self, password):
"""Überprüft, ob das Passwort übereinstimmt"""
return check_password_hash(self.password_hash, password)
def __repr__(self):
return f'<User {self.username}>'
# user_loader definieren: Flask-Login verwendet diese Funktion, um das User-Objekt aus der Session wiederherzustellen
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
UserMixin fügt automatisch die folgenden Attribute und Methoden in das User-Modell ein:
| Attribute/Methoden | Beschreibung |
|---|---|
| is_authenticated | Ob der Benutzer angemeldet ist |
| is_active | Ob der Benutzer aktiv ist |
| is_anonymous | Ob es sich um einen anonymen Benutzer handelt (nicht angemeldet) |
| get_id() | Die Primärschlüssel-ID des Benutzers abrufen |
Migration generieren und ausführen:
(venv) $ flask db migrate -m "新增 User 模型" (venv) $ flask db upgrade
Ein Authentifizierungs-Blueprint erstellen
Beispiel
from flask import Blueprint, render_template, redirect, url_for, request, flash
from flask_login import login_user, logout_user, login_required, current_user
from app.models import User, db
auth_bp = Blueprint('auth', __name__)
@auth_bp.route("/register", methods=['GET', 'POST'])
def register():
"""Benutzerregistrierung"""
if current_user.is_authenticated:
return redirect(url_for('main.index'))
if request.method == 'POST':
username = request.form.get('username', '').strip()
email = request.form.get('email', '').strip()
password = request.form.get('password', '')
# Erforderliche Felder validieren
if not username or not email or not password:
flash('Alle Felder müssen ausgefüllt werden.', 'error')
return render_template('register.html')
# Prüfen, ob Benutzername und E-Mail bereits existieren
if User.query.filter_by(username=username).first():
flash('Benutzername ist bereits vergeben.', 'error')
return render_template('register.html')
if User.query.filter_by(email=email).first():
flash('E-Mail ist bereits registriert.', 'error')
return render_template('register.html')
# Benutzer erstellen
user = User(username=username, email=email)
user.set_password(password) # Passwort hashen und speichern
db.session.add(user)
db.session.commit()
login_user(user) # Nach der Registrierung automatisch anmelden
flash(f'Registrierung erfolgreich, willkommen, {username}!', 'success')
return redirect(url_for('main.index'))
return render_template('register.html')
@auth_bp.route("/login", methods=['GET', 'POST'])
def login():
"""Benutzeranmeldung"""
if current_user.is_authenticated:
return redirect(url_for('main.index'))
if request.method == 'POST':
username = request.form.get('username', '').strip()
password = request.form.get('password', '')
# user_loader sucht den Benutzer in der Datenbank
user = User.query.filter_by(username=username).first()
# Passwort überprüfen (das Passwort selbst wird nicht in Logs aufgezeichnet)
if user is None or not user.check_password(password):
flash(Falscher Benutzername oder falsches Passwort., 'error')
return render_template('login.html')
login_user(user, remember=request.form.get('remember'))
flash(f'Willkommen zurück, {username}!', 'success')
# Nach dem Login zur vor dem Login besuchten Seite weiterleiten (der Parameter next in der URL)
next_page = request.args.get('next')
return redirect(next_page or url_for('main.index'))
return render_template('login.html')
@auth_bp.route("/logout")
@login_required # Nur angemeldete Benutzer können sich abmelden
def logout():
logout_user()
flash('Sicher abgemeldet.', 'info')
return redirect(url_for('main.index'))
Für das App-Design benötigte Referenzen
Beispiel
from app.blueprints.auth import auth_bp
app.register_blueprint(auth_bp)
Passwörter niemals im Klartext speichern!
generate_password_hash()Verwende den PBKDF2-Algorithmus, um Passwörter mit Salt zu hashen. Selbst wenn die Datenbank geleakt wird, können Angreifer das Passwort nicht zurückrechnen. Verwende beim Verifizieren des Passwortscheck_password_hash()。
Login- und Registrierungs-Templates erstellen
Beispiel
{% extends 'base.html' %}
{% block title %}Anmeldung - EXAMPLE Blog{% endblock %}
{% block content %}
<div class="auth-form">
<h2>Anmelden</h2>
<form method="post">
<div class="form-group">
<label>Benutzername</label>
<input type="text" name="username" required>
</div>
<div class="form-group">
<label>Passwort</label>
<input type="password" name="password" required>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="remember">Angemeldet bleiben
</label>
</div>
<button type="submit" class="btn-submit">Anmelden</button>
</Form>
<p class="form-footer">
Noch kein Konto?<a href="{{ url_for('auth.register') }}">Jetzt registrieren</a>
</p>
</div>
{% endblock %}
Navigationsleiste aktualisieren, um den Anmeldestatus anzuzeigen
Beispiel
<nav>
<a href="/">Startseite</a>
{% if current_user.is_authenticated %}
<span class="user-name">{{ current_user.username }}</span>
<a href="{{ url_for('auth.logout') }}">Abmelden</a>
{% else %}
<a href="{{ url_for('auth.login') }}">Anmelden</a>
<a href="{{ url_for('auth.register') }}">Registrieren</a>
{% endif %}
</nav>
current_userEs ist ein Proxy-Objekt, das automatisch von Flask-Login injiziert wird und direkt in allen Templates und View-Funktionen verwendet werden kann. Wenn man angemeldet ist, ist es ein User-Objekt; wenn man nicht angemeldet ist, ist es eine AnonymousUserMixin-Instanz.
Kapitelzusammenfassung
In diesem Kapitel haben Sie die Flask-Login-Session-Authentifizierung integriert: UserMixin + user_loader banden das Benutzermodell ein, login_user/logout_user verwalteten die Session, werkzeug hashte Passwörter, @login_required schützte Views, und current_user in Templates prüfte den Status.
Jetzt hat der Blog einen vollständigen Ablauf für Benutzerregistrierung, Anmeldung und Abmeldung.
Weitere Erweiterungen