"""API 层共享依赖:DB session、当前登录用户。""" from __future__ import annotations import logging from typing import Annotated from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from sqlalchemy.orm import Session from app.core.security import TokenError, decode_token from app.db.session import get_db from app.models.user import User logger = logging.getLogger("shagua.deps") # auto_error=True → 没传 Authorization header 时直接 403。但我们想 401, # 所以手动 auto_error=False + raise HTTPException _bearer = HTTPBearer(auto_error=False, scheme_name="Bearer") def get_current_user( credentials: Annotated[HTTPAuthorizationCredentials | None, Depends(_bearer)], db: Annotated[Session, Depends(get_db)], ) -> User: """从 Authorization: Bearer 解出当前 user。 失败时统一 401,WWW-Authenticate 头让客户端知道要重新登录。 """ if credentials is None or credentials.scheme.lower() != "bearer": raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="missing bearer token", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = decode_token(credentials.credentials, expected_type="access") except TokenError as e: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e), headers={"WWW-Authenticate": "Bearer"}, ) from e user_id = int(payload["sub"]) user = db.get(User, user_id) if user is None or user.status != "active": raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="user not found or disabled", headers={"WWW-Authenticate": "Bearer"}, ) return user CurrentUser = Annotated[User, Depends(get_current_user)] DbSession = Annotated[Session, Depends(get_db)]