Major changes: - New frontend (platform/web/): Vite + React 18 + TypeScript + Tailwind - 4-module navigation: 数据送标 / 模型管理 / 车队管理 / 系统管理 - Data catalog with charts (DMS/ADAS/Lane 3-tab view) - Quality review workflow (标注质检): Good/Fine/Bad scoring with auto-advance - Audit enhancements: batch operations, rejection categories, Feishu notifications - Operation audit log (操作日志) - World model simulation studio (仿真工坊) - Dataset version management with snapshots and diff - ADAS 7-class dataset integration (138K images organized + compressed) - User management with Feishu integration and pagination - CRUD/search/filter on all pages, card layout redesign - PIL-optimized image overlay rendering - Auto-snapshot on build, in_review workflow stage - Removed embedded algorithm code (now in workspace)
74 lines
2.3 KiB
Python
74 lines
2.3 KiB
Python
"""FastAPI 认证依赖。"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Annotated
|
|
|
|
from fastapi import Depends, HTTPException, status
|
|
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
|
from sqlalchemy.orm import Session, joinedload
|
|
|
|
from as_platform.auth.jwt import decode_access_token
|
|
from as_platform.config import DEV_AUTH_ENABLED
|
|
from as_platform.db.engine import get_db
|
|
from as_platform.db.init_db import user_has_permission
|
|
from as_platform.db.models import Role, User
|
|
|
|
_bearer = HTTPBearer(auto_error=False)
|
|
|
|
|
|
def _load_user(db: Session, user_id: int) -> User | None:
|
|
return (
|
|
db.query(User)
|
|
.options(joinedload(User.roles).joinedload(Role.permissions))
|
|
.filter(User.id == user_id, User.is_active.is_(True))
|
|
.first()
|
|
)
|
|
|
|
|
|
def get_current_user_optional(
|
|
creds: Annotated[HTTPAuthorizationCredentials | None, Depends(_bearer)],
|
|
db: Annotated[Session, Depends(get_db)],
|
|
) -> User | None:
|
|
if not creds:
|
|
return None
|
|
payload = decode_access_token(creds.credentials)
|
|
if not payload or "sub" not in payload:
|
|
return None
|
|
return _load_user(db, int(payload["sub"]))
|
|
|
|
|
|
def get_current_user(
|
|
user: Annotated[User | None, Depends(get_current_user_optional)],
|
|
) -> User:
|
|
if not user:
|
|
raise HTTPException(status.HTTP_401_UNAUTHORIZED, detail="未登录,请先飞书登录")
|
|
return user
|
|
|
|
|
|
def require_permission(permission: str):
|
|
def _dep(user: Annotated[User, Depends(get_current_user)]) -> User:
|
|
if not user_has_permission(user, permission):
|
|
raise HTTPException(status.HTTP_403_FORBIDDEN, detail=f"缺少权限: {permission}")
|
|
return user
|
|
|
|
return _dep
|
|
|
|
|
|
def require_any_permission(*permissions: str):
|
|
def _dep(user: Annotated[User, Depends(get_current_user)]) -> User:
|
|
if any(user_has_permission(user, p) for p in permissions):
|
|
return user
|
|
raise HTTPException(status.HTTP_403_FORBIDDEN, detail="权限不足")
|
|
|
|
return _dep
|
|
|
|
|
|
def can_submit_action(user: User, action: str) -> bool:
|
|
if user_has_permission(user, "write:approval_submit"):
|
|
return True
|
|
if action == "register_batch" and user_has_permission(user, "write:approval_submit:register"):
|
|
return True
|
|
if action == "delivery_ingest" and user_has_permission(user, "write:delivery_submit"):
|
|
return True
|
|
return False
|