from typing import Annotated, Optional from fastapi import Depends, HTTPException, status, Request from fastapi.security import OAuth2PasswordBearer from jose import jwt, JWTError from app.core.config import settings from app.domain.schemas.user import UserInDB, TokenPayload from app.infra.repositories.user_repository import UserRepository from app.infra.db.postgresql.database import Database oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.API_V1_STR}/auth/login") # 数据库依赖 async def get_db(request: Request) -> Database: """ 获取数据库实例 从 FastAPI app.state 中获取在启动时初始化的数据库连接 """ if not hasattr(request.app.state, "db"): raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Database not initialized" ) return request.app.state.db async def get_user_repository(db: Database = Depends(get_db)) -> UserRepository: """获取用户仓储实例""" return UserRepository(db) async def get_current_user( token: str = Depends(oauth2_scheme), user_repo: UserRepository = Depends(get_user_repository) ) -> UserInDB: """ 获取当前登录用户 从 JWT Token 中解析用户信息,并从数据库验证 """ credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]) username: str = payload.get("sub") token_type: str = payload.get("type", "access") if username is None: raise credentials_exception if token_type != "access": raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token type. Access token required.", headers={"WWW-Authenticate": "Bearer"}, ) except JWTError: raise credentials_exception # 从数据库获取用户 user = await user_repo.get_user_by_username(username) if user is None: raise credentials_exception return user async def get_current_active_user( current_user: UserInDB = Depends(get_current_user), ) -> UserInDB: """ 获取当前活跃用户(必须是激活状态) """ if not current_user.is_active: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Inactive user" ) return current_user async def get_current_superuser( current_user: UserInDB = Depends(get_current_user), ) -> UserInDB: """ 获取当前超级管理员用户 """ if not current_user.is_superuser: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Not enough privileges. Superuser access required." ) return current_user