From c924753210467c676b47209cfda0c37e49557f7e Mon Sep 17 00:00:00 2001 From: Luckaskl Date: Thu, 28 May 2026 14:56:25 -0500 Subject: [PATCH] agoravaisedeusquiser --- app/core/security.py | 50 ++++++++++++++++++-------------------------- app/main.py | 12 +++++++++-- jwtpdf.md | 1 + 3 files changed, 31 insertions(+), 32 deletions(-) create mode 100644 jwtpdf.md diff --git a/app/core/security.py b/app/core/security.py index 4ef5107..13d76ae 100644 --- a/app/core/security.py +++ b/app/core/security.py @@ -1,10 +1,12 @@ -from fastapi import Depends, HTTPException, status -from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials +from fastapi import Request import jwt from pydantic import BaseModel from app.core.config import settings +import textwrap -security = HTTPBearer() +class AuthException(Exception): + def __init__(self, message: str): + self.message = message class UserAuth(BaseModel): id: str @@ -16,17 +18,25 @@ def format_public_key(key: str) -> str: footer = "-----END PUBLIC KEY-----" if header in key and footer in key: - # Extrai o miolo, remove todos os espaços e quebras de linha body = key.replace(header, "").replace(footer, "") body = "".join(body.split()) + body = "\n".join(textwrap.wrap(body, width=64)) return f"{header}\n{body}\n{footer}" return key -def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)) -> UserAuth: - token = credentials.credentials +def get_current_user(request: Request) -> UserAuth: + auth_header = request.headers.get("authorization") + + if not auth_header: + raise AuthException("Missing Authorization header") + + parts = auth_header.split(" ") + if len(parts) != 2 or parts[0].lower() != "bearer": + raise AuthException("Authorization must be Bearer token") + + token = parts[1] try: - # Garante que a chave terá o formato PEM válido, independentemente de como foi definida no .env public_key = format_public_key(settings.JWT_PUBLIC_KEY_PEM) payload = jwt.decode( @@ -39,30 +49,10 @@ def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(securit 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"}, - ) + raise AuthException("Invalid token claims") 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 as e: import traceback - traceback.print_exc() # Imprime no log do docker para ajudar a debugar - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=f"Could not validate credentials: {str(e)}", - headers={"WWW-Authenticate": "Bearer"}, - ) + traceback.print_exc() + raise AuthException("Invalid or expired access token") diff --git a/app/main.py b/app/main.py index 75ddac6..810d8e1 100644 --- a/app/main.py +++ b/app/main.py @@ -1,6 +1,7 @@ -from fastapi import FastAPI, Depends +from fastapi import FastAPI, Depends, Request from fastapi.middleware.cors import CORSMiddleware -from app.core.security import get_current_user, UserAuth +from fastapi.responses import JSONResponse +from app.core.security import get_current_user, UserAuth, AuthException from app.core.config import settings from app.api.v1.api import api_router from app.db.database import Base, engine @@ -23,6 +24,13 @@ app.add_middleware( app.include_router(api_router, prefix=settings.API_V1_STR) +@app.exception_handler(AuthException) +async def auth_exception_handler(request: Request, exc: AuthException): + return JSONResponse( + status_code=401, + content={"message": exc.message} + ) + @app.get("/") def root(current_user: UserAuth = Depends(get_current_user)): return {"message": "Bem-vindo ao Microsserviço de Catálogo do GameVerse"} diff --git a/jwtpdf.md b/jwtpdf.md new file mode 100644 index 0000000..1b30804 --- /dev/null +++ b/jwtpdf.md @@ -0,0 +1 @@ +2. O que validar Para toda rota protegida: Authorization ler extrair Bearer validar assinatura RS256 com JWT_PUBLIC_KEY_PEM 1 Guia: validar JWT nos serviços consumidoresvalidar iss , aud e exp validar se sub existe request.auth = { id: sub, token } montar Se algo falhar, retornar 401 . 3) Exemplo prático (Node/Express + jose) import express from 'express' import { importSPKI, jwtVerify } from 'jose' const app = express() const ISSUER = process.env.JWT_ISSUER! const AUDIENCE = process.env.JWT_AUDIENCE! const PUBLIC_KEY_PEM = process.env.JWT_PUBLIC_KEY_PEM!.repl ace(/\\n/g, '\n') let publicKeyPromise: ReturnType | null = null function getPublicKey() { if (!publicKeyPromise) { publicKeyPromise = importSPKI(PUBLIC_KEY_PEM, 'RS256') } return publicKeyPromise } function authMiddleware() { return async (req, res, next) => { try { const authHeader = req.header('authorization') if (!authHeader) { return res.status(401).json({ message: 'Missing Aut horization header' }) } 2 Guia: validar JWT nos serviços consumidoresconst [scheme, token] = authHeader.split(' ') if (!scheme || !token || scheme.toLowerCase() !== 'be arer') { return res.status(401).json({ message: 'Authorizati on must be Bearer token' }) } const publicKey = await getPublicKey() const { payload } = await jwtVerify(token, publicKey, { issuer: ISSUER, audience: AUDIENCE, algorithms: ['RS256'] }) if (typeof payload.sub !== 'string' || !payload.sub.t rim()) { return res.status(401).json({ message: 'Invalid tok en claims' }) } req.auth = { id: payload.sub, token } return next() } catch { return res.status(401).json({ message: 'Invalid or ex pired access token' }) } } } // middleware em todas requisições que lidam com dados do u 3 Guia: validar JWT nos serviços consumidoressuário app.get('/profile/me', authMiddleware(), (req, res) => { return res.json({ userId: req.auth.id }) }) 4) Propagação entre serviços (A -> B) Se for necessário, serviços podem se comunicar entre si. Quando a API A chamar a API B em nome do usuário: repasse o mesmo Authorization: Bearer a API B valida esse token com JWT_PUBLIC_KEY_PEM (mesmo conteúdo do ) a API B usa sub como identidade confiável .env o serviço que recebe a requisição extrai o token e válida ele (conforme procedimento acima): // extração do token por meio do header const authHeader = req.header('authorization') 5) Checklist rápido middleware valida assinatura + iss + aud + exp sub obrigatório, é ele que referencia o ID do usuário autenticado retorna 401 para token ausente/inválido/expirado usa sub como ID confiável