implementação da validação por jwt

This commit is contained in:
2026-05-28 09:46:53 -05:00
parent f148d430b3
commit a4cbc28d1d
6 changed files with 211 additions and 3 deletions

View File

@@ -8,6 +8,7 @@ import unicodedata
from app.schemas.game import GameCreate, GameUpdate, GameResponse, StandardResponse
from app.models.game import Game
from app.db.database import get_db
from app.core.security import get_current_user, UserAuth
router = APIRouter()
@@ -38,7 +39,7 @@ def read_games(skip: int = 0, limit: int = 100, genre: Optional[str] = None, pla
return {"success": True, "message": "Lista de jogos", "data": data}
@router.post("/", response_model=StandardResponse, status_code=status.HTTP_201_CREATED)
def create_game(game: GameCreate, db: Session = Depends(get_db)):
def create_game(game: GameCreate, db: Session = Depends(get_db), current_user: UserAuth = Depends(get_current_user)):
slug = generate_slug(game.title)
# Verifica se já existe um jogo com esse slug
@@ -71,7 +72,7 @@ def read_game(id_ou_slug: str, db: Session = Depends(get_db)):
return {"success": True, "message": "Detalhes do jogo", "data": data}
@router.patch("/{id}", response_model=StandardResponse)
def update_game(id: int, game: GameUpdate, db: Session = Depends(get_db)):
def update_game(id: int, game: GameUpdate, db: Session = Depends(get_db), current_user: UserAuth = Depends(get_current_user)):
db_game = db.query(Game).filter(Game.id == id).first()
if not db_game:
@@ -98,7 +99,7 @@ def update_game(id: int, game: GameUpdate, db: Session = Depends(get_db)):
return {"success": True, "message": "Jogo atualizado com sucesso", "data": data}
@router.delete("/{id_ou_slug}", response_model=StandardResponse)
def delete_game(id_ou_slug: str, db: Session = Depends(get_db)):
def delete_game(id_ou_slug: str, db: Session = Depends(get_db), current_user: UserAuth = Depends(get_current_user)):
if id_ou_slug.isdigit():
db_game = db.query(Game).filter(Game.id == int(id_ou_slug)).first()
else:

View File

@@ -4,6 +4,11 @@ class Settings(BaseSettings):
PROJECT_NAME: str = "Microsserviço de Catálogo de Jogos"
API_V1_STR: str = "/api/v1"
DATABASE_URL: str
# Configurações de JWT
JWT_ISSUER: str
JWT_AUDIENCE: str
JWT_PUBLIC_KEY_PEM: str
class Config:
env_file = ".env"

54
app/core/security.py Normal file
View File

@@ -0,0 +1,54 @@
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
from pydantic import BaseModel
from app.core.config import settings
security = HTTPBearer()
class UserAuth(BaseModel):
id: str
token: str
def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)) -> UserAuth:
token = credentials.credentials
try:
# A chave pública pode vir com '\n' escapado do .env
public_key = settings.JWT_PUBLIC_KEY_PEM.replace('\\n', '\n')
payload = jwt.decode(
token,
public_key,
algorithms=["RS256"],
issuer=settings.JWT_ISSUER,
audience=settings.JWT_AUDIENCE
)
sub = payload.get("sub")
if not sub or not str(sub).strip():
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token claims",
headers={"WWW-Authenticate": "Bearer"},
)
return UserAuth(id=str(sub), token=token)
except jwt.ExpiredSignatureError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token expired",
headers={"WWW-Authenticate": "Bearer"},
)
except jwt.InvalidTokenError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid access token",
headers={"WWW-Authenticate": "Bearer"},
)
except Exception:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)