74 lines
2.1 KiB
Python
74 lines
2.1 KiB
Python
"""
|
||
鉴权依赖注入
|
||
|
||
JWT 验证、当前用户、角色检查。
|
||
"""
|
||
|
||
from enum import Enum
|
||
|
||
from fastapi import Depends, HTTPException, status
|
||
from fastapi.security import OAuth2PasswordBearer
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
from sqlalchemy.future import select
|
||
|
||
from ..database import get_db
|
||
from ..models import User, UserStatus # noqa: E402
|
||
from ..services.auth import AuthService, has_any_role
|
||
|
||
|
||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/login")
|
||
|
||
|
||
async def get_current_user(
|
||
token: str = Depends(oauth2_scheme),
|
||
db: AsyncSession = Depends(get_db),
|
||
) -> User:
|
||
"""从 JWT 解析并返回当前认证用户"""
|
||
credentials_exception = HTTPException(
|
||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||
detail="Could not validate credentials",
|
||
headers={"WWW-Authenticate": "Bearer"},
|
||
)
|
||
|
||
username = AuthService.verify_token(token)
|
||
if username is None:
|
||
raise credentials_exception
|
||
|
||
result = await db.execute(select(User).where(User.username == username))
|
||
user = result.scalar_one_or_none()
|
||
|
||
if user is None:
|
||
raise credentials_exception
|
||
|
||
return user
|
||
|
||
|
||
async def get_current_active_user(
|
||
current_user: User = Depends(get_current_user),
|
||
) -> User:
|
||
"""当前活跃用户(排除 AWAY / OFFLINE)"""
|
||
if (not getattr(current_user, "is_active", True)) or current_user.status != UserStatus.ACTIVE:
|
||
raise HTTPException(status_code=403, detail="User is not active")
|
||
return current_user
|
||
|
||
|
||
def require_roles(*roles: str):
|
||
"""依赖工厂:要求用户具备指定角色之一"""
|
||
|
||
async def role_checker(
|
||
current_user: User = Depends(get_current_user),
|
||
) -> User:
|
||
user_role = (
|
||
current_user.role.value
|
||
if isinstance(current_user.role, Enum)
|
||
else current_user.role
|
||
)
|
||
if not has_any_role(user_role, list(roles)):
|
||
raise HTTPException(
|
||
status_code=status.HTTP_403_FORBIDDEN,
|
||
detail=f"Access denied. Required roles: {', '.join(roles)}",
|
||
)
|
||
return current_user
|
||
|
||
return role_checker
|