""" FastAPI 依赖注入:从 JWT 提取当前用户信息。 用法: @router.get("/protected") async def protected_endpoint(user: CurrentUser = Depends(get_current_user)): print(user.user_id, user.site_id) """ from dataclasses import dataclass from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from jose import JWTError from app.auth.jwt import decode_access_token # Bearer token 提取器 _bearer_scheme = HTTPBearer(auto_error=True) @dataclass(frozen=True) class CurrentUser: """从 JWT 解析出的当前用户上下文。""" user_id: int site_id: int async def get_current_user( credentials: HTTPAuthorizationCredentials = Depends(_bearer_scheme), ) -> CurrentUser: """ FastAPI 依赖:从 Authorization header 提取 JWT,验证后返回用户信息。 失败时抛出 401。 """ token = credentials.credentials try: payload = decode_access_token(token) except JWTError: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="无效的令牌", headers={"WWW-Authenticate": "Bearer"}, ) user_id_raw = payload.get("sub") site_id = payload.get("site_id") if user_id_raw is None or site_id is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="令牌缺少必要字段", headers={"WWW-Authenticate": "Bearer"}, ) try: user_id = int(user_id_raw) except (TypeError, ValueError): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="令牌中 user_id 格式无效", headers={"WWW-Authenticate": "Bearer"}, ) return CurrentUser(user_id=user_id, site_id=site_id)