""" 认证中间件和依赖 """ from fastapi import Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from packages.domain.auth import jwt_service from packages.domain.entities import User from apps.api.app.dependencies import get_container security = HTTPBearer() async def get_current_user( credentials: HTTPAuthorizationCredentials = Depends(security), ) -> User: """ 获取当前登录用户 从 Authorization header 中提取 JWT token 并验证 Raises: HTTPException: Token 无效或过期 Returns: 当前用户对象 """ token = credentials.credentials try: # 验证 token payload = jwt_service.verify_token(token) user_id = payload.get("sub") if not user_id: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token: missing user_id", headers={"WWW-Authenticate": "Bearer"}, ) # 从数据库获取用户 container = get_container() user = container.user_repository.find_by_id(user_id) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found", headers={"WWW-Authenticate": "Bearer"}, ) return user except Exception as e: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=f"Invalid token: {str(e)}", headers={"WWW-Authenticate": "Bearer"}, ) async def get_current_user_optional( credentials: HTTPAuthorizationCredentials = Depends(HTTPBearer(auto_error=False)), ) -> User | None: """ 获取当前登录用户(可选) 如果没有提供 token,返回 None 而不是抛出异常 Returns: 当前用户对象或 None """ if not credentials: return None try: return await get_current_user(credentials) except HTTPException: return None def require_workspace_access(workspace_id: str, user: User = Depends(get_current_user)) -> tuple[str, str]: """ 要求用户可以访问指定工作空间 Args: workspace_id: 工作空间 ID user: 当前用户 Raises: HTTPException: 用户没有访问权限 Returns: (workspace_id, user_role) """ container = get_container() permission_checker = container.permission_checker has_access, role = permission_checker.check_workspace_access(workspace_id, user.id) if not has_access: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="You don't have access to this workspace", ) return workspace_id, role def require_workspace_admin(workspace_id: str, user: User = Depends(get_current_user)) -> str: """ 要求用户是工作空间的 Admin 或 Owner Args: workspace_id: 工作空间 ID user: 当前用户 Raises: HTTPException: 用户没有管理权限 Returns: workspace_id """ container = get_container() permission_checker = container.permission_checker if not permission_checker.check_is_admin_or_owner(workspace_id, user.id): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Only workspace owner or admin can perform this action", ) return workspace_id def require_workspace_owner(workspace_id: str, user: User = Depends(get_current_user)) -> str: """ 要求用户是工作空间的 Owner Args: workspace_id: 工作空间 ID user: 当前用户 Raises: HTTPException: 用户不是 Owner Returns: workspace_id """ container = get_container() permission_checker = container.permission_checker if not permission_checker.check_is_owner(workspace_id, user.id): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Only workspace owner can perform this action", ) return workspace_id