microdot.login — Benutzeranmeldungsablauf

Ein übergeordneter Wrapper um microdot.session, der den herkömmlichen Anmeldungsablauf mit Benutzername / Passwort implementiert: ein user loader-Callback bildet die in der Session gespeicherte Benutzer-ID auf das Benutzerobjekt der Anwendung ab, Routen-Dekoratoren leiten nicht authentifizierte Anfragen auf eine konfigurierbare Login-URL um, und optionale „Remember me“-Cookies lassen wiederkehrende Besucher über Browser-Sitzungen hinweg angemeldet bleiben.

Erfordert, dass microdot.session in der Anwendung initialisiert ist, bevor das Login-Objekt erzeugt wird – in der Session wird die Benutzer-ID gespeichert.

class Login

class microdot.login.Login(login_url: str = '/login')
login_url

URL, auf die der Dekorator nicht authentifizierte Anfragen umleitet. Die Anwendung stellt das eigentliche Login-Formular / den Handler unter dieser Route bereit. Standard '/login'.

user_loader(f)

Dekorator, der den Benutzer-Resolver-Callback registriert. f erhält die in der Session gespeicherte Benutzer-ID und gibt das Benutzerobjekt zurück (oder None, wenn die ID nicht mehr gültig ist – ein gelöschtes Konto, eine widerrufene Session usw.).

login = Login()

@login.user_loader
async def load_user(user_id):
    return users.get(user_id)
__call__(f)

Das Dekorieren einer Route mit der Login-Instanz stellt sie hinter eine Authentifizierung:

@app.get('/dashboard')
@login
async def dashboard(request):
    user = request.g.current_user
    # ...

Nicht authentifizierte Anfragen werden mit einem Abfrageparameter ?next=<original-url> auf login_url umgeleitet, sodass der Login-Handler den Benutzer dorthin zurücksenden kann, wo er hergekommen ist.

fresh(f)

Wie __call__(), lehnt aber Sessions ab, die aus einem „Remember me“-Cookie wiederhergestellt wurden – der Benutzer muss sich seit dem letzten vollständigen Login ausdrücklich angemeldet haben. Wird verwendet, um sensible Routen (Passwortänderung, Kontolöschung) abzusichern, damit ein gestohlener Remember-me-Cookie sie nicht erreichen kann.

async login_user(request, user, remember: bool | int = False, redirect_url: str = '/')

Markiert user für request als angemeldet. Speichert die Benutzer-ID in der Session und gibt eine Weiterleitungsantwort zurück.

user

Das vom User-Loader zurückgegebene Benutzerobjekt. Muss ein id-Attribut haben.

remember

Wenn wahr, wird außerdem ein langlebiger _remember-Cookie gesetzt. Übergib True für die standardmäßigen 30 Tage oder eine ganze Zahl für die Anzahl der Tage, die der Cookie bestehen soll.

redirect_url

Wohin nach dem Login umgeleitet werden soll. Wird durch ?next=<url> aus der ursprünglichen Anfrage überschrieben, wenn es auf einen Same-Site-Pfad verweist.

Gibt die Weiterleitungsantwort zurück – gib ihren Wert aus dem Login-Routen-Handler zurück.

async logout_user(request)

Entfernt die Benutzer-ID aus der Session und löscht jeden _remember-Cookie. Aus einer /logout-Route verwenden:

@app.post('/logout')
async def logout(request):
    await login.logout_user(request)
    return redirect('/')
async get_current_user(request)

Gibt das aktuell angemeldete Benutzerobjekt zurück (oder None). Wird in request.g.current_user memoisiert, sodass wiederholte Aufrufe innerhalb einer Anfrage den Loader nur einmal erreichen.

Beispiel

Ein minimaler Anmeldungsablauf:

from microdot import Microdot, redirect
from microdot.session import Session
from microdot.login import Login

app = Microdot()
Session(app, secret_key=load_secret())
login = Login()

@login.user_loader
async def load_user(user_id):
    return users.get(user_id)

@app.get('/login')
async def login_page(request):
    return Response.send_file('static/login.html')

@app.post('/login')
async def do_login(request):
    user = authenticate(request.form['user'], request.form['pass'])
    if not user:
        return redirect('/login?error=1')
    return await login.login_user(request, user, remember=True)

@app.get('/dashboard')
@login
async def dashboard(request):
    return 'hi ' + request.g.current_user.name

@app.post('/logout')
async def logout(request):
    await login.logout_user(request)
    return redirect('/')

Der _remember-Cookie ist selbst ein signiertes JWT (mithilfe des Session-Geheimnisses), sodass ein gestohlener Cookie nicht in einer anderen Anwendung oder nach einer Rotation des Geheimnisses wiederverwendet werden kann.