feat: rotas de login/logoff (app/routers/auth.py)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Gustavo
2026-08-13 20:38:43 -03:00
co-authored by Claude Sonnet 5
parent 1b80290f6f
commit c4079b3e47
3 changed files with 177 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
from app import session
from app.auth import NaoAutenticado, UsuarioLogado, exigir_login
from app.routers import auth as router_auth
app_teste = FastAPI()
app_teste.include_router(router_auth.router)
@app_teste.exception_handler(NaoAutenticado)
def _handler(request, exc):
from fastapi.responses import RedirectResponse
return RedirectResponse(url=f"/login?next={exc.caminho_original}", status_code=303)
@app_teste.get("/rota-protegida-teste")
def _rota_protegida(usuario: UsuarioLogado = Depends(exigir_login)):
return {"ok": True}
client = TestClient(app_teste, follow_redirects=False)
CSRF_TESTE = "teste-csrf-token"
client.cookies.set("csrf_token", CSRF_TESTE)
def test_get_login_mostra_formulario():
resposta = client.get("/login")
assert resposta.status_code == 200
assert "senha" in resposta.text.lower()
def test_post_login_credenciais_corretas_grava_cookie_e_redireciona():
resposta = client.post(
"/login", data={"usuario": "admin", "senha": "teste123", "next": "/clientes", "csrf_token": CSRF_TESTE}
)
assert resposta.status_code == 303
assert resposta.headers["location"] == "/clientes"
assert session.SESSION_COOKIE_NAME in resposta.cookies
def test_post_login_sem_next_redireciona_para_clientes():
resposta = client.post("/login", data={"usuario": "admin", "senha": "teste123", "csrf_token": CSRF_TESTE})
assert resposta.status_code == 303
assert resposta.headers["location"] == "/clientes"
def test_post_login_next_externo_e_ignorado_por_seguranca():
resposta = client.post(
"/login",
data={"usuario": "admin", "senha": "teste123", "next": "https://site-malicioso.com", "csrf_token": CSRF_TESTE},
)
assert resposta.status_code == 303
assert resposta.headers["location"] == "/clientes"
def test_post_login_credenciais_erradas_nao_grava_cookie():
resposta = client.post(
"/login", data={"usuario": "admin", "senha": "errada", "csrf_token": CSRF_TESTE}
)
assert resposta.status_code == 200
assert "inválid" in resposta.text.lower()
assert session.SESSION_COOKIE_NAME not in resposta.cookies
def test_get_rota_protegida_sem_login_redireciona_para_login():
# Testes anteriores deixaram um painel_session válido no cookie jar do
# client (persistente, como um navegador real) — limpa antes de simular
# a requisição de um visitante não autenticado.
client.cookies.delete(session.SESSION_COOKIE_NAME)
resposta = client.get("/rota-protegida-teste")
assert resposta.status_code == 303
assert resposta.headers["location"] == "/login?next=/rota-protegida-teste"
def test_post_logout_apaga_cookie_e_redireciona():
cookies = {session.SESSION_COOKIE_NAME: session.criar_token("admin", "Admin", "ADMIN")}
resposta = client.post("/logout", data={"csrf_token": CSRF_TESTE}, cookies=cookies)
assert resposta.status_code == 303
assert resposta.headers["location"] == "/login"
# cookie apagado: o Set-Cookie da resposta zera o valor
set_cookie = resposta.headers.get("set-cookie", "")
assert session.SESSION_COOKIE_NAME in set_cookie