Mejorar verificacion por email y OAuth de Google para despliegue en sinbad2.

Endurece el envio SMTP (EHLO/STARTTLS, timeouts, errores tipados y logging), centraliza el manejo de fallos en registro y reenvio, codifica la redirect_uri de Google OAuth y documenta la configuracion de produccion en .env.example.
This commit is contained in:
Mireya Cueto Garrido
2026-05-21 12:14:17 +02:00
parent 2b7428df56
commit 6d87a32bc4
4 changed files with 230 additions and 53 deletions
+45 -14
View File
@@ -1,3 +1,5 @@
import logging
import os
from datetime import datetime
from bson import ObjectId
@@ -10,7 +12,11 @@ from api.models.user_models import (
UserCreate,
UserLogin,
)
from api.services.email_service import send_verification_email
from api.services.email_service import (
EmailConfigurationError,
EmailDeliveryError,
send_verification_email,
)
from api.utils.email_verification import (
MAX_EMAIL_VERIFICATION_ATTEMPTS,
generate_verification_code,
@@ -27,6 +33,40 @@ from api.utils.security import (
)
router = APIRouter(prefix="/auth", tags=["auth"])
logger = logging.getLogger(__name__)
def _env_bool(name: str, default: str = "false") -> bool:
return os.getenv(name, default).strip().lower() in {"1", "true", "yes", "on"}
def _email_send_error_detail(exc: Exception) -> str:
if _env_bool("EMAIL_VERIFICATION_SHOW_ERRORS"):
return f"No se pudo enviar el correo de verificación: {exc}"
return "No se pudo enviar el correo de verificación"
async def _dispatch_verification_email(email: str, username: str, code: str) -> None:
try:
sent = send_verification_email(email, username, code)
except (EmailConfigurationError, EmailDeliveryError) as exc:
logger.error("Fallo al enviar verificación a %s: %s", email, exc)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=_email_send_error_detail(exc),
) from exc
except Exception as exc:
logger.exception("Error inesperado al enviar verificación a %s", email)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=_email_send_error_detail(exc),
) from exc
if not sent:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="No se pudo enviar el correo de verificación",
)
@router.post("/register")
@@ -68,13 +108,10 @@ async def register_user(user: UserCreate):
result = await users_collection.insert_one(user_doc)
try:
send_verification_email(email, user.username, verification_code)
except Exception as exc:
await _dispatch_verification_email(email, user.username, verification_code)
except HTTPException:
await users_collection.delete_one({"_id": result.inserted_id})
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="No se pudo enviar el correo de verificación",
) from exc
raise
return {
"message": "Usuario registrado. Revisa tu correo para verificar la cuenta.",
@@ -214,13 +251,7 @@ async def resend_verification_email(payload: EmailVerificationResendRequest):
},
)
try:
send_verification_email(email, user["username"], verification_code)
except Exception as exc:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="No se pudo enviar el correo de verificación",
) from exc
await _dispatch_verification_email(email, user["username"], verification_code)
return {"message": "Nuevo código de verificación enviado"}
+14 -5
View File
@@ -1,9 +1,11 @@
from datetime import datetime, timedelta
from urllib.parse import quote
import httpx
import jwt
import os
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import RedirectResponse
from datetime import datetime, timedelta
import httpx
import os
import jwt
from api.database.mongodb import users_collection
@@ -17,11 +19,18 @@ FRONTEND_URL = os.getenv("FRONTEND_URL", "http://localhost:5173")
@router.get("/login")
async def google_login():
if not GOOGLE_CLIENT_ID or not REDIRECT_URI:
raise HTTPException(
status_code=500,
detail="GOOGLE_CLIENT_ID o GOOGLE_REDIRECT_URI no configurados",
)
redirect_uri = quote(REDIRECT_URI, safe="")
google_auth_url = (
"https://accounts.google.com/o/oauth2/auth"
"?response_type=code"
f"&client_id={GOOGLE_CLIENT_ID}"
f"&redirect_uri={REDIRECT_URI}"
f"&redirect_uri={redirect_uri}"
"&scope=openid%20email%20profile"
"&access_type=offline"
"&prompt=consent"