Files
MoviePilot/app/api/dependencies/auth.py
T

117 lines
3.8 KiB
Python

"""用户身份、授权与认证服务依赖。"""
from typing import Any
from fastapi import Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Session
from app.adapters.web.security.access import verify_token
from app.api.data import get_async_db, get_db
from app.api.dependencies.data import repository, standalone_repository
from app.application.security.auth import AuthService
from app.application.security.passkeys import PasskeyService
from app.application.security.user import UserService
from app.schemas.token import TokenPayload as _SchemaTokenPayload
def get_user_service(
db: AsyncSession = Depends(get_async_db),
) -> UserService:
"""组装用户管理应用服务。"""
return UserService(repository=repository("user", db))
def get_auth_service() -> AuthService:
"""组装同步认证应用服务。"""
return AuthService(
users=standalone_repository("user"),
config=standalone_repository("system_config"),
passkeys=standalone_repository("passkey"),
)
def get_passkey_service() -> PasskeyService:
"""组装 PassKey 应用服务。"""
return PasskeyService(repository=standalone_repository("passkey"))
def get_current_user(
db: Session = Depends(get_db),
token_data: _SchemaTokenPayload = Depends(verify_token),
) -> Any:
"""读取令牌对应用户,不存在时返回 403。"""
user = repository("user", db).get_by_id(token_data.sub)
if not user:
raise HTTPException(status_code=403, detail="用户不存在")
return user
async def get_current_user_async(
db: AsyncSession = Depends(get_async_db),
token_data: _SchemaTokenPayload = Depends(verify_token),
) -> Any:
"""异步读取令牌对应用户,不存在时返回 403。"""
user = await repository("user", db).async_get_by_id(token_data.sub)
if not user:
raise HTTPException(status_code=403, detail="用户不存在")
return user
def get_current_active_user(
current_user: Any = Depends(get_current_user),
) -> Any:
"""校验并返回当前激活用户。"""
if not current_user.is_active:
raise HTTPException(status_code=403, detail="用户未激活")
return current_user
async def get_current_active_user_async(
current_user: Any = Depends(get_current_user_async),
) -> Any:
"""异步校验并返回当前激活用户。"""
if not current_user.is_active:
raise HTTPException(status_code=403, detail="用户未激活")
return current_user
def _ensure_manage_user(current_user: Any) -> Any:
"""校验用户具备全局管理权限。"""
permissions = current_user.permissions or {}
if not current_user.is_superuser and not bool(permissions.get("manage")):
raise HTTPException(status_code=400, detail="用户权限不足")
return current_user
def get_current_active_manage_user(
current_user: Any = Depends(get_current_active_user),
) -> Any:
"""返回当前拥有管理权限的激活用户。"""
return _ensure_manage_user(current_user)
async def get_current_active_manage_user_async(
current_user: Any = Depends(get_current_active_user_async),
) -> Any:
"""异步返回当前拥有管理权限的激活用户。"""
return _ensure_manage_user(current_user)
def get_current_active_superuser(
current_user: Any = Depends(get_current_user),
) -> Any:
"""校验并返回当前激活超级管理员。"""
if not current_user.is_superuser:
raise HTTPException(status_code=400, detail="用户权限不足")
return current_user
async def get_current_active_superuser_async(
current_user: Any = Depends(get_current_user_async),
) -> Any:
"""异步校验并返回当前激活超级管理员。"""
if not current_user.is_superuser:
raise HTTPException(status_code=400, detail="用户权限不足")
return current_user