Deploy inicial: API FastAPI + infra Podman/Caddy + docs

- App FastAPI (main.py, app/): rotas /health e /dados_retorno, middleware anti-scanner, logging configurado
- Config via configs.json (Pydantic); segredos fora do codigo e do git (.gitignore)
- Dockerfile (oracledb thin, HEALTHCHECK) + requirements.txt + .dockerignore
- Deploy Podman/Quadlet + Caddy em deploy/
- Docs: CLAUDE.md + docs/ (arquitetura, deploy, known-issues)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ricardo Leite 2026-07-28 16:37:13 -03:00
commit 15c89c9038
22 changed files with 1397 additions and 0 deletions

57
app/security.py Normal file
View file

@ -0,0 +1,57 @@
from datetime import datetime, timedelta, timezone
import jwt
from app.config import settings
from app.infra.database import db_instance
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
ALGORITHM = "HS256"
TOKEN_EXPIRE_MINUTES = 5
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
def criar_token(data: dict) -> str:
payload = data.copy()
payload["exp"] = datetime.now(timezone.utc) + timedelta(
minutes=TOKEN_EXPIRE_MINUTES
)
return jwt.encode(payload, settings.api.jwt_secret, algorithm=ALGORITHM)
def verificar_credenciais(client_id: str, client_secret: str) -> bool:
db_instance.create_pool()
assert db_instance.pool is not None
conn = db_instance.pool.acquire()
try:
cursor = conn.cursor()
cursor.execute(
"""
SELECT 1
FROM orvel_ti.CAD_USUARIO
WHERE PERFIL_TI = 'operador_ti'
AND ativo = 'S'
AND API = 'S'
AND login = :login
AND senha = :senha
""",
{"login": client_id, "senha": client_secret},
)
return cursor.fetchone() is not None
finally:
db_instance.pool.release(conn)
async def token_valido(token: str = Depends(oauth2_scheme)) -> dict:
try:
payload = jwt.decode(token, settings.api.jwt_secret, algorithms=[ALGORITHM])
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expirado"
)
except jwt.InvalidTokenError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Token inválido"
)