167 lines
4.4 KiB
Python
167 lines
4.4 KiB
Python
"""
|
|
Legacy auth middleware.
|
|
|
|
Disabled because it depends on the removed DI container. Rebuild it around the
|
|
canonical JWT settings and SQLAlchemy-backed user repository before reuse.
|
|
"""
|
|
|
|
raise RuntimeError("apps.api.app.middleware.auth is disabled: rebuild auth dependency wiring before importing it")
|
|
|
|
from fastapi import Depends, HTTPException, status
|
|
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
|
|
|
from apps.api.app.dependencies import get_container
|
|
from packages.domain.auth import jwt_service
|
|
from packages.domain.entities import User
|
|
|
|
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
|