feat(backend): 重构 HTTP 错误处理为 RFC7807 标准并优化多个 service
This commit is contained in:
@@ -4,7 +4,7 @@ import asyncio
|
||||
from typing import Annotated
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import Depends, Header, HTTPException
|
||||
from fastapi import Depends, Header
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.auth.jwt_verifier import (
|
||||
@@ -14,6 +14,7 @@ from core.auth.jwt_verifier import (
|
||||
from core.auth.models import CurrentUser
|
||||
from core.config.settings import config
|
||||
from core.db import get_db
|
||||
from core.http.errors import ApiProblemError
|
||||
from core.logging import get_logger
|
||||
from services.base.supabase import supabase_service
|
||||
from v1.auth.gateway import SupabaseAuthGateway
|
||||
@@ -44,7 +45,11 @@ def get_jwt_verifier() -> JwtVerifier:
|
||||
)
|
||||
if not issuer or not jwt_secret:
|
||||
logger.error("JWT validation failed: verifier config not configured")
|
||||
raise HTTPException(status_code=503, detail="JWT verifier not configured")
|
||||
raise ApiProblemError(
|
||||
status_code=503,
|
||||
code="JWT_VERIFIER_NOT_CONFIGURED",
|
||||
detail="JWT verifier not configured",
|
||||
)
|
||||
_jwt_verifier = JwtVerifier(
|
||||
issuer=issuer,
|
||||
jwt_secret=jwt_secret,
|
||||
@@ -90,16 +95,24 @@ async def get_current_user(
|
||||
) -> CurrentUser:
|
||||
if not authorization:
|
||||
logger.warning("JWT validation failed: missing authorization header")
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
raise ApiProblemError(
|
||||
status_code=401,
|
||||
code="AUTH_UNAUTHORIZED",
|
||||
detail="Unauthorized",
|
||||
)
|
||||
|
||||
scheme, _, token = authorization.partition(" ")
|
||||
if scheme.lower() != "bearer" or not token:
|
||||
logger.warning("JWT validation failed: invalid authorization scheme")
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
raise ApiProblemError(
|
||||
status_code=401,
|
||||
code="AUTH_UNAUTHORIZED",
|
||||
detail="Unauthorized",
|
||||
)
|
||||
|
||||
try:
|
||||
payload = get_jwt_verifier().verify(token)
|
||||
except HTTPException:
|
||||
except ApiProblemError:
|
||||
raise
|
||||
except TokenValidationError as exc:
|
||||
logger.warning(
|
||||
@@ -109,20 +122,32 @@ async def get_current_user(
|
||||
)
|
||||
fallback_user = await _verify_user_with_supabase(token)
|
||||
if fallback_user is None:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized") from exc
|
||||
raise ApiProblemError(
|
||||
status_code=401,
|
||||
code="AUTH_UNAUTHORIZED",
|
||||
detail="Unauthorized",
|
||||
) from exc
|
||||
logger.info("JWT fallback validation succeeded", user_id=str(fallback_user.id))
|
||||
return fallback_user
|
||||
|
||||
subject = payload.get("sub")
|
||||
if not isinstance(subject, str) or not subject:
|
||||
logger.warning("JWT validation failed: missing or invalid subject claim")
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
raise ApiProblemError(
|
||||
status_code=401,
|
||||
code="AUTH_UNAUTHORIZED",
|
||||
detail="Unauthorized",
|
||||
)
|
||||
|
||||
try:
|
||||
user_id = UUID(subject)
|
||||
except ValueError:
|
||||
logger.warning("JWT validation failed: invalid UUID in subject")
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
raise ApiProblemError(
|
||||
status_code=401,
|
||||
code="AUTH_UNAUTHORIZED",
|
||||
detail="Unauthorized",
|
||||
)
|
||||
|
||||
logger.debug("JWT validation successful", user_id=str(user_id))
|
||||
phone = payload.get("phone") if isinstance(payload.get("phone"), str) else None
|
||||
|
||||
Reference in New Issue
Block a user