diff --git a/app/core/deps.py b/app/core/deps.py new file mode 100644 index 0000000..0dd343c --- /dev/null +++ b/app/core/deps.py @@ -0,0 +1,43 @@ +from fastapi import Depends, Header, HTTPException, status +from sqlalchemy.orm import Session + +from app.core.jwt import decode_token +from app.db import get_db +from app.models import User + + +# Читает заголовок Authorization: Bearer , +# декодирует, ищет пользователя по sub, проверяет is_active; +# при ошибке бросает HTTPException(401); +def get_current_user( + authorization: str | None = Header(default=None), + db: Session = Depends(get_db), +) -> User: + if not authorization or not authorization.lower().startswith("bearer "): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail="Authentication required" + ) + token = authorization.split(" ", 1)[1] + try: + payload = decode_token(token) + except ValueError as exc: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token" + ) from exc + + sub = payload.get("sub") + user = db.get(User, int(sub)) if isinstance(sub, str) and sub.isdigit() else None + if user is None or not user.is_active: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token" + ) + return user + + +# обёртка над get_current_user, дополнительно проверяет is_admin, иначе HTTPException(403) +def require_admin(user: User = Depends(get_current_user)) -> User: + if not user.is_admin: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="Admin privileges required" + ) + return user