microdot.login — flusso di login utente

Un wrapper di livello superiore attorno a microdot.session che implementa il flusso di login convenzionale con nome utente / password: un callback user loader mappa l’id utente memorizzato nella sessione all’oggetto utente dell’applicazione, i decoratori di route reindirizzano le richieste non autenticate a un URL di login configurabile, e i cookie «remember me» opzionali consentono ai visitatori che ritornano di rimanere autenticati tra le sessioni del browser.

Richiede che microdot.session sia inizializzato sull’applicazione prima che venga costruito l’oggetto login – la sessione è il punto in cui viene memorizzato l’id utente.

class Login

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

URL a cui il decoratore reindirizza le richieste non autenticate. L’applicazione fornisce il form/handler di login effettivo su questa route. Predefinito '/login'.

user_loader(f)

Decoratore che registra il callback di risoluzione utente. f riceve l’id utente memorizzato nella sessione e restituisce l’oggetto utente (oppure None se l’id non è più valido – un account eliminato, una sessione revocata, ecc.).

login = Login()

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

Decorare una route con l’istanza Login la protegge dietro l’autenticazione:

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

Le richieste non autenticate vengono reindirizzate a login_url con un parametro di query ?next=<original-url> in modo che l’handler di login possa rimandare l’utente da dove proveniva.

fresh(f)

Come __call__(), ma rifiuta le sessioni ripristinate da un cookie «remember me» – l’utente deve aver effettuato esplicitamente il login dall’ultimo login completo. Utilizzato per proteggere le route sensibili (cambio password, eliminazione account) in modo che un cookie remember-me rubato non possa raggiungerle.

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

Contrassegna user come autenticato per request. Memorizza l’id utente nella sessione e restituisce una risposta di reindirizzamento.

user

L’oggetto utente restituito dallo user loader. Deve avere un attributo id.

remember

Se truthy, imposta anche un cookie _remember di lunga durata. Passa True per i 30 giorni predefiniti, oppure un intero per il numero di giorni di durata del cookie.

redirect_url

Dove reindirizzare dopo il login. Sovrascritto da ?next=<url> della richiesta originale se punta a un percorso same-site.

Restituisce la risposta di reindirizzamento – restituisci il suo valore dall’handler della route di login.

async logout_user(request)

Rimuove l’id utente dalla sessione ed elimina qualsiasi cookie _remember. Da utilizzare da una route /logout

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

Restituisce l’oggetto dell’utente attualmente autenticato (oppure None). Memoizzato su request.g.current_user in modo che chiamate ripetute all’interno di una stessa richiesta accedano al loader una sola volta.

Esempio

Un flusso di login minimale:

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('/')

Il cookie _remember è esso stesso un JWT firmato (usando il segreto della sessione), quindi un cookie rubato non può essere riutilizzato su un’applicazione diversa né dopo che il segreto è stato ruotato.