feat(): Criado url protegida por token, acesso via endpoint

This commit is contained in:
Kenio 2025-11-12 16:11:44 -03:00
parent 9f6b340412
commit 73dd1ac3bd
3 changed files with 46 additions and 14 deletions

View file

@ -31,9 +31,22 @@ def generate_storage_hash() -> str:
# Função que gera o token temporário para acesso ao documento # Função que gera o token temporário para acesso ao documento
# def generate_temporary_token(
# expires_minutes: int,
# secret_key: str,
# algorithm: str,
# ) -> str:
# """Gera um token JWT válido por poucos minutos."""
# expire = datetime.utcnow() + timedelta(minutes=expires_minutes)
# payload = {
# "exp": expire,
# }
# return jwt.encode(payload, secret_key, algorithm=algorithm)
def generate_temporary_token( def generate_temporary_token(
file_id: str, file_id: str,
filename: str, file_path: str,
expires_minutes: int, expires_minutes: int,
secret_key: str, secret_key: str,
algorithm: str, algorithm: str,
@ -42,7 +55,7 @@ def generate_temporary_token(
expire = datetime.utcnow() + timedelta(minutes=expires_minutes) expire = datetime.utcnow() + timedelta(minutes=expires_minutes)
payload = { payload = {
"sub": file_id, "sub": file_id,
"filename": filename, "filename": file_path, # caminho relativo completo
"exp": expire, "exp": expire,
} }
return jwt.encode(payload, secret_key, algorithm=algorithm) return jwt.encode(payload, secret_key, algorithm=algorithm)

View file

@ -1,22 +1,45 @@
from fastapi import APIRouter, Query, HTTPException from fastapi import APIRouter, Query, HTTPException
from fastapi.responses import FileResponse from fastapi.responses import FileResponse
from jose import jwt, JWTError from jose import jwt, JWTError
from database.mysql import SessionLocal, get_database_settings
from pathlib import Path
router = APIRouter() router = APIRouter()
# === Configuração do token temporário ===
DB_SETTINGS = get_database_settings()
SECRET_KEY = getattr(DB_SETTINGS, "aeskey", None)
ALGORITHM = "HS256"
@router.get("/{file_id}/{filename}") # Pasta base onde os arquivos são armazenados
def visualizar_arquivo(file_id: str, filename: str, token: str = Query(...)): STORAGE_DIR = Path("storage")
"""Valida o token e retorna o arquivo se autorizado."""
@router.get("/{file_id}/{file_path:path}")
def visualizar_arquivo(file_id: str, file_path: str, token: str = Query(...)):
"""
Valida o token e retorna o arquivo do storage, se autorizado.
Exemplo de URL:
/view/d7e8f9g0h1i2/100/57/documento.pdf?token=xxxx
"""
# --- 1. Valida token JWT ---
try: try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
if payload["sub"] != file_id or payload["filename"] != filename: if payload["sub"] != file_id or payload["filename"] != file_path:
raise HTTPException(status_code=403, detail="Token inválido.") raise HTTPException(status_code=403, detail="Token inválido.")
except JWTError: except JWTError:
raise HTTPException(status_code=401, detail="Token expirado ou inválido.") raise HTTPException(status_code=401, detail="Token expirado ou inválido.")
file_path = f"files/{filename}" # --- 2. Monta caminho real no disco ---
try: full_path = STORAGE_DIR / file_path
return FileResponse(file_path, media_type="application/pdf")
except FileNotFoundError: # --- 3. Retorna arquivo, se existir ---
if not full_path.exists():
raise HTTPException(status_code=404, detail="Arquivo não encontrado.") raise HTTPException(status_code=404, detail="Arquivo não encontrado.")
return FileResponse(
full_path,
media_type="application/pdf",
headers={"Content-Disposition": "inline"}, # abre no navegador
)

View file

@ -117,8 +117,6 @@ class ShowAtosRepository:
"url": ( "url": (
f"{URL_API}/view/{generate_storage_hash()}/{d.url.decode('utf-8')}?token=" f"{URL_API}/view/{generate_storage_hash()}/{d.url.decode('utf-8')}?token="
+ generate_temporary_token( + generate_temporary_token(
generate_storage_hash(),
d.url.decode("utf-8"),
10, 10,
SECRET_KEY, SECRET_KEY,
ALGORITHM, ALGORITHM,
@ -188,8 +186,6 @@ class ShowAtosRepository:
"url": ( "url": (
f"{URL_API}/view/{generate_storage_hash()}/{d.url.decode('utf-8')}?token=" f"{URL_API}/view/{generate_storage_hash()}/{d.url.decode('utf-8')}?token="
+ generate_temporary_token( + generate_temporary_token(
generate_storage_hash(),
d.url.decode("utf-8"),
10, 10,
SECRET_KEY, SECRET_KEY,
ALGORITHM, ALGORITHM,