microdot.login — fluxo de login de usuário

Um wrapper de mais alto nível em torno de microdot.session que implementa o fluxo convencional de login com nome de usuário / senha: um callback carregador de usuário mapeia o user-id armazenado na sessão de volta para o objeto de usuário da aplicação, decoradores de rota redirecionam requisições não autenticadas para uma URL de login configurável, e cookies opcionais de “lembrar de mim” permitem que visitantes recorrentes permaneçam conectados entre sessões do navegador.

Requer que microdot.session esteja inicializado na aplicação antes de o objeto de login ser construído – a sessão é onde o user-id é armazenado.

class Login

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

URL para a qual o decorador redireciona requisições não autenticadas. A aplicação fornece o formulário/manipulador de login real nesta rota. Padrão '/login'.

user_loader(f)

Decorador que registra o callback de resolução de usuário. f recebe o user-id armazenado na sessão e retorna o objeto de usuário (ou None se o id não for mais válido – uma conta excluída, uma sessão revogada, etc.).

login = Login()

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

Decorar uma rota com a instância de Login a protege por trás da autenticação:

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

Requisições não autenticadas são redirecionadas para login_url com um parâmetro de consulta ?next=<original-url> para que o manipulador de login possa enviar o usuário de volta para onde estava.

fresh(f)

Como __call__(), mas rejeita sessões restauradas a partir de um cookie de “lembrar de mim” – o usuário deve ter feito login explicitamente desde o último login completo. Usado para proteger rotas sensíveis (alteração de senha, exclusão de conta) de modo que um cookie de lembrar-de-mim roubado não consiga alcançá-las.

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

Marca user como conectado para request. Armazena o id do usuário na sessão e retorna uma resposta de redirecionamento.

user

O objeto de usuário retornado pelo carregador de usuário. Deve ter um atributo id.

remember

Se verdadeiro, também define um cookie _remember de longa duração. Passe True para os 30 dias padrão, ou um inteiro para o número de dias que o cookie deve durar.

redirect_url

Para onde redirecionar após o login. Sobrescrito por ?next=<url> da requisição original se apontar para um caminho do mesmo site.

Retorna a resposta de redirecionamento – retorne seu valor a partir do manipulador da rota de login.

async logout_user(request)

Limpa o id do usuário da sessão e remove qualquer cookie _remember. Use a partir de uma rota /logout

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

Retorna o objeto do usuário atualmente conectado (ou None). Memorizado em request.g.current_user para que chamadas repetidas dentro de uma requisição acessem o carregador apenas uma vez.

Exemplo

Um fluxo de login mínimo:

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

O cookie _remember é, ele próprio, um JWT assinado (usando o segredo da sessão), de modo que um cookie roubado não pode ser reutilizado em uma aplicação diferente ou após o segredo ter sido rotacionado.