Files
mnote/wolai-backend/app/deps.py
T

65 lines
2.3 KiB
Python
Raw Permalink Normal View History

2025-11-23 10:55:04 +08:00
from __future__ import annotations
from dataclasses import dataclass
from typing import Optional
try: # Python 3.9+
from typing import Annotated # type: ignore[attr-defined]
except ImportError: # Python 3.8 fallback
from typing_extensions import Annotated
import httpx
from fastapi import Depends, Header, HTTPException, status
from app.config import settings
@dataclass
class AuthContext:
user_id: str
access_token: str
async def get_current_user(
authorization: Annotated[Optional[str], Header(convert_underscores=False)] = None,
2025-12-06 16:47:17 +08:00
x_supabase_access_token: Annotated[
Optional[str], Header(convert_underscores=False, alias="x-supabase-access-token")
] = None,
2025-11-23 10:55:04 +08:00
) -> AuthContext:
"""
验证 Supabase JWTstage0 直接依赖 service_role 解析 token。
生产环境应通过 API Gateway 注入 user。
"""
2025-12-06 16:47:17 +08:00
header_token = authorization or (f"Bearer {x_supabase_access_token}" if x_supabase_access_token else None)
if not header_token or not header_token.startswith("Bearer "):
2025-11-23 10:55:04 +08:00
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing bearer token")
2025-12-06 16:47:17 +08:00
token = header_token.replace("Bearer ", "", 1).strip()
2025-11-23 10:55:04 +08:00
if not token:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Empty token")
2025-12-06 16:47:17 +08:00
print(f"[auth] Validating Supabase token prefix={token[:8]}")
2025-11-23 10:55:04 +08:00
auth_url = f"{settings.supabase_url.rstrip('/')}/auth/v1/user"
2025-12-06 16:47:17 +08:00
apikey = settings.supabase_anon_key or settings.supabase_service_role_key
2025-11-23 10:55:04 +08:00
headers = {
"Authorization": f"Bearer {token}",
2025-12-06 16:47:17 +08:00
"apikey": apikey,
2025-11-23 10:55:04 +08:00
}
async with httpx.AsyncClient(timeout=10.0) as client:
try:
response = await client.get(auth_url, headers=headers)
response.raise_for_status()
except httpx.HTTPError as exc: # pragma: no cover - 网络异常
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid Supabase token") from exc
data = response.json()
user_id = data.get("id") or data.get("user", {}).get("id")
if not user_id:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid Supabase token")
return AuthContext(user_id=str(user_id), access_token=token)
AuthDep = Annotated[AuthContext, Depends(get_current_user)]