from collections.abc import Callable from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from sqlalchemy.orm import Session from app.database import get_db from app.models import PersonRole, Personnel, Role from app.security import verify_token from app.services.serializers import temporary_expired bearer = HTTPBearer(auto_error=False) def current_user( credentials: HTTPAuthorizationCredentials | None = Depends(bearer), db: Session = Depends(get_db), ) -> Personnel: if credentials is None: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="未登录") try: payload = verify_token(credentials.credentials) except ValueError as exc: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="登录已失效") from exc phone = payload.get("sub") try: role = Role(payload.get("role")) except ValueError as exc: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="角色无效") from exc user = db.get(Personnel, phone) if user is None: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="人员不存在") if temporary_expired(user): raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="临时工已过期,请微信授权续期") if db.get(PersonRole, {"phone": phone, "role": role}) is None: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="角色不存在") user.role = role return user def require_roles(*roles: Role) -> Callable[[Personnel], Personnel]: def checker(user: Personnel = Depends(current_user)) -> Personnel: if user.role not in roles: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="无权限") return user return checker