rebase
This commit is contained in:
64
app/api/deps.py
Normal file
64
app/api/deps.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""Shared API dependencies: current user, admin guard, db session, settings."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from typing import Any
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.security import decode_token
|
||||
from app.core.settings_service import get_all_settings
|
||||
from app.db import get_db
|
||||
from app.models import User
|
||||
|
||||
_bearer = HTTPBearer(auto_error=False)
|
||||
|
||||
|
||||
async def get_current_user(
|
||||
creds: HTTPAuthorizationCredentials | None = Depends(_bearer),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
) -> User:
|
||||
"""Resolve the JWT bearer token to a User row.
|
||||
|
||||
Raises 401 on missing/invalid/expired token.
|
||||
"""
|
||||
if creds is None or creds.scheme.lower() != "bearer":
|
||||
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Missing bearer token")
|
||||
try:
|
||||
payload = decode_token(creds.credentials)
|
||||
except Exception as e: # noqa: BLE001
|
||||
raise HTTPException(status.HTTP_401_UNAUTHORIZED, f"Invalid token: {e}")
|
||||
if payload.get("type") != "access":
|
||||
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Wrong token type")
|
||||
user_id_str = payload.get("sub")
|
||||
if not user_id_str:
|
||||
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Token missing sub")
|
||||
try:
|
||||
user_id = uuid.UUID(user_id_str)
|
||||
except ValueError:
|
||||
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Invalid user id in token")
|
||||
|
||||
user = (
|
||||
await db.execute(select(User).where(User.id == user_id))
|
||||
).scalar_one_or_none()
|
||||
if user is None:
|
||||
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "User not found")
|
||||
if not user.is_active:
|
||||
raise HTTPException(status.HTTP_403_FORBIDDEN, "Account disabled")
|
||||
return user
|
||||
|
||||
|
||||
async def require_admin(user: User = Depends(get_current_user)) -> User:
|
||||
"""Require an admin user."""
|
||||
if not user.is_admin:
|
||||
raise HTTPException(status.HTTP_403_FORBIDDEN, "Admin only")
|
||||
return user
|
||||
|
||||
|
||||
async def get_settings_dict(db: AsyncSession = Depends(get_db)) -> dict[str, Any]:
|
||||
"""FastAPI dependency: returns the full settings dict."""
|
||||
return await get_all_settings(db)
|
||||
Reference in New Issue
Block a user