diff --git a/webapi/api/endpoints/v1/auths.py b/webapi/api/endpoints/v1/auths.py index 793a5b4..b3cc367 100644 --- a/webapi/api/endpoints/v1/auths.py +++ b/webapi/api/endpoints/v1/auths.py @@ -4,7 +4,7 @@ from typing import Optional from passlib.hash import sha256_crypt from db.db_connection import get_session -from auth.auth_service import authenticate_user, crear_jwt, validar_jwt +from auth.auth_service import authenticate_user, crear_jwt, validar_jwt, get_current_user from infrastructure.email.smtp_service import send_email import secrets import base64 @@ -43,11 +43,8 @@ def login(request: LoginRequest, session: Session = Depends(get_session)): @router.get("/profile") -def profile(authorization: Optional[str] = Header(None)): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") - return {"profile darta": data} +def profile(current_user: dict = Depends(get_current_user)): + return {"profile data": current_user} @router.post("/generate") async def generate_password( diff --git a/webapi/api/endpoints/v1/prompts.py b/webapi/api/endpoints/v1/prompts.py index cba625e..00d777c 100644 --- a/webapi/api/endpoints/v1/prompts.py +++ b/webapi/api/endpoints/v1/prompts.py @@ -4,7 +4,7 @@ from models.user import User from models.prompts import Prompts from db.db_connection import get_session -from auth.auth_service import validar_jwt +from auth.auth_service import get_current_user from infrastructure.email.smtp_service import send_email router = APIRouter() @@ -13,12 +13,9 @@ async def create_prompt( prompt: Prompts, session: Session = Depends(get_session), - authorization: Optional[str] = Header(None), + current_user: dict = Depends(get_current_user), send_email_header: Optional[str] = Header("false", alias="send_email") ): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") # Ensure the user exists before creating a prompt user = session.get(User, prompt.user_id) if not user: @@ -40,10 +37,7 @@ async def create_prompt( @router.get("", response_model=list[Prompts]) def read_prompts(skip: int = 0, limit: int = 10, session: Session = Depends(get_session), - authorization: Optional[str] = Header(None)): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") + current_user: dict = Depends(get_current_user)): statement = select(Prompts).offset(skip).limit(limit) prompts = session.exec(statement).all() if not prompts: @@ -53,10 +47,7 @@ def read_prompts(skip: int = 0, limit: int = 10, @router.get("/{prompt_id}", response_model=Prompts) def get_prompt(prompt_id: int, session: Session = Depends(get_session), - authorization: Optional[str] = Header(None)): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") + current_user: dict = Depends(get_current_user)): prompt = session.get(Prompts, prompt_id) if not prompt: raise HTTPException(status_code=404, detail="Prompt not found") @@ -65,10 +56,7 @@ def get_prompt(prompt_id: int, session: Session = Depends(get_session), @router.put("/{prompt_id}", response_model=Prompts) def update_prompt(prompt_id: int, prompt: Prompts, session: Session = Depends(get_session), - authorization: Optional[str] = Header(None)): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") + current_user: dict = Depends(get_current_user)): existing_prompt = session.get(Prompts, prompt_id) if not existing_prompt: raise HTTPException(status_code=404, detail="Prompt not found") @@ -88,10 +76,7 @@ def update_prompt(prompt_id: int, prompt: Prompts, @router.delete("/{prompt_id}") def delete_prompt(prompt_id: int, session: Session = Depends(get_session), - authorization: Optional[str] = Header(None)): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") + current_user: dict = Depends(get_current_user)): prompt = session.get(Prompts, prompt_id) if not prompt: raise HTTPException(status_code=404, detail="Prompt not found to delete") diff --git a/webapi/api/endpoints/v1/users.py b/webapi/api/endpoints/v1/users.py index bb68e09..eff8518 100644 --- a/webapi/api/endpoints/v1/users.py +++ b/webapi/api/endpoints/v1/users.py @@ -1,10 +1,10 @@ -from fastapi import APIRouter, HTTPException, Depends, Header +from fastapi import APIRouter, HTTPException, Depends from sqlmodel import Session, select from models.user import User from typing import Optional from schemas.user_schema import UserReadWithPrompts from db.db_connection import get_session -from auth.auth_service import validar_jwt +from auth.auth_service import get_current_user from passlib.hash import sha256_crypt @@ -15,10 +15,7 @@ @router.get("", response_model=list[User]) def read_users(phone: Optional[int] = None, skip: int = 0, limit: int = 10, session: Session = Depends(get_session), - authorization: Optional[str] = Header(None)): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") + current_user: dict = Depends(get_current_user)): statement = select(User).offset(skip).limit(limit) # If phone is provided, filter by phone number if phone: @@ -31,10 +28,7 @@ def read_users(phone: Optional[int] = None, skip: int = 0, limit: int = 10, @router.get("/{user_id}", response_model=User) def get_user(user_id: int, session: Session = Depends(get_session), - authorization: Optional[str] = Header(None)): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") + current_user: dict = Depends(get_current_user)): user = session.get(User, user_id) if not user: raise HTTPException(status_code=404, detail="User not found") @@ -43,10 +37,7 @@ def get_user(user_id: int, session: Session = Depends(get_session), @router.get("/prompts/{user_id}", response_model=UserReadWithPrompts) def get_user_with_prompts(user_id: int, session: Session = Depends(get_session), - authorization: Optional[str] = Header(None)): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") + current_user: dict = Depends(get_current_user)): statement = select(User).where(User.id == user_id) result = session.exec(statement) user = result.one_or_none() @@ -59,10 +50,7 @@ def get_user_with_prompts(user_id: int, session: Session = Depends(get_session), @router.put("/{user_id}", response_model=User) def update_user(user_id: int, user: User, session: Session = Depends(get_session), - authorization: Optional[str] = Header(None)): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") + current_user: dict = Depends(get_current_user)): user.name = user.name.lower() user.last_name = user.last_name.lower() existing_user = session.get(User, user_id) @@ -85,10 +73,7 @@ def update_user(user_id: int, user: User, @router.delete("/{user_id}") def delete_user(user_id: int, session: Session = Depends(get_session), - authorization: Optional[str] = Header(None)): - data = validar_jwt(authorization) - if not data: - raise HTTPException(status_code=401, detail="Unauthorized token") + current_user: dict = Depends(get_current_user)): try: user = session.get(User, user_id) if not user: diff --git a/webapi/auth/auth_service.py b/webapi/auth/auth_service.py index f8d556b..4b9c6fa 100644 --- a/webapi/auth/auth_service.py +++ b/webapi/auth/auth_service.py @@ -1,4 +1,5 @@ from fastapi import HTTPException, Depends +from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from typing import Optional from sqlmodel import Session, select from models.user import User @@ -42,7 +43,7 @@ def crear_jwt(data: dict): token = jwt.encode(payload, SECRET_KEY, algorithm="HS256") return token -# Validar un token +# Validar un token con prefijo "Bearer" (compatibilidad legado) def validar_jwt(token: str): try: if not token: @@ -61,4 +62,33 @@ def validar_jwt(token: str): return None except Exception: return None + + +# Validar token puro (sin prefijo "Bearer") +def validar_jwt_raw(token: str): + try: + if not token: + return None + decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256"]) + return decoded["data"] + except jwt.ExpiredSignatureError: + return None + except jwt.InvalidTokenError: + return None + except Exception: + return None + + +# Esquema HTTPBearer — registra el Security Scheme en OpenAPI (/docs) +bearer_scheme = HTTPBearer() + + +def get_current_user( + credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme), +): + """Dependencia reutilizable para endpoints protegidos con Bearer token.""" + data = validar_jwt_raw(credentials.credentials) + if not data: + raise HTTPException(status_code=401, detail="Unauthorized token") + return data \ No newline at end of file