Files
GTI_GERENCIADOR_FISCAL/app/routers/auth.py
T
2026-08-13 20:38:43 -03:00

63 lines
2.3 KiB
Python

"""
Rotas de login/logoff. O painel não usa mais HTTP Basic Auth (ver
app/auth.py) — quem não está logado é redirecionado para GET /login pelo
exception handler de NaoAutenticado (registrado em app/main.py).
"""
from typing import Optional
from urllib.parse import urlencode
from fastapi import APIRouter, Depends, Form, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from .. import session
from ..auth import UsuarioLogado, autenticar_credenciais, exigir_login
from ..csrf import exigir_csrf, token_do_contexto
router = APIRouter()
templates = Jinja2Templates(directory="app/templates")
def _proximo_seguro(next_: Optional[str]) -> str:
"""Só aceita um path interno (começa com "/", sem "//") — nunca uma URL
externa, para não virar um open redirect via POST /login?next=..."""
if next_ and next_.startswith("/") and not next_.startswith("//"):
return next_
return "/clientes"
@router.get("/login", response_class=HTMLResponse)
def form_login(request: Request, next: Optional[str] = None):
return templates.TemplateResponse(
request, "login.html", {"csrf_token": token_do_contexto(request), "next": next or ""}
)
@router.post("/login", dependencies=[Depends(exigir_csrf)])
def login(
request: Request,
usuario: str = Form(...),
senha: str = Form(...),
next: Optional[str] = Form(None),
):
usuario_logado = autenticar_credenciais(usuario, senha)
if usuario_logado is None:
return templates.TemplateResponse(
request,
"login.html",
{"csrf_token": token_do_contexto(request), "next": next or "", "erro": "Usuário ou senha inválidos."},
)
destino = _proximo_seguro(next)
resposta = RedirectResponse(url=destino, status_code=303)
token = session.criar_token(usuario_logado.login, usuario_logado.nome, usuario_logado.perfil)
resposta.set_cookie(session.SESSION_COOKIE_NAME, token, httponly=True, samesite="lax")
return resposta
@router.post("/logout", dependencies=[Depends(exigir_csrf)])
def logout(usuario: UsuarioLogado = Depends(exigir_login)):
resposta = RedirectResponse(url="/login", status_code=303)
resposta.delete_cookie(session.SESSION_COOKIE_NAME)
return resposta