""" 依赖注入工具 ============ """ from __future__ import annotations from collections.abc import AsyncGenerator from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.config import get_settings from app.core.security import verify_access_token from app.db.session import get_db as db_session from app.models.user import User settings = get_settings() security = HTTPBearer(auto_error=False) # 数据库依赖 async def get_db() -> AsyncGenerator[AsyncSession]: """获取数据库 Session""" async for session in db_session(): yield session async def get_current_user( credentials: HTTPAuthorizationCredentials | None = Depends(security), db: AsyncSession = Depends(get_db), ) -> User: """从 Authorization Header 中提取 JWT Access Token 并验证。""" if credentials is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="缺少认证信息", headers={"WWW-Authenticate": "Bearer"}, ) token = credentials.credentials payload = verify_access_token(token) if not payload or not payload.get("sub"): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Token 无效或已过期", headers={"WWW-Authenticate": "Bearer"}, ) user_id = payload.get("sub") result = await db.execute(select(User).where(User.id == user_id)) user = result.scalar_one_or_none() if user is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="用户不存在", headers={"WWW-Authenticate": "Bearer"}, ) if not user.is_active: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="账号已被封禁", headers={"WWW-Authenticate": "Bearer"}, ) return user async def get_current_user_optional( credentials: HTTPAuthorizationCredentials | None = Depends(security), db=Depends(get_db), ) -> User | None: """ 获取当前登录用户(可选,未登录返回 None) """ if credentials is None: return None try: return await get_current_user(credentials, db) except HTTPException: return None