"""Аутентификация через gnexus-auth и гейт админки по ролям.
Токены gnexus-auth — opaque (не JWT), валидация только «call home»:
GET /oauth/userinfo с Bearer-токеном. Отзыв токена и блокировка
пользователя учитываются сервером auth мгновенно.
Доступ к админке — system_role in ("admin", "superadmin").
"""
from fastapi import Depends, HTTPException, Request, status
from gnexus_gauth.config import GAuthConfig
from gnexus_gauth.dto import AuthenticatedUser
from gnexus_gauth.runtime import HttpRuntimeUserProvider
from app.config import Settings, get_settings
ADMIN_ROLES = ("admin", "superadmin")
_user_provider: HttpRuntimeUserProvider | None = None
def _get_user_provider(settings: Settings) -> HttpRuntimeUserProvider:
"""Один провайдер на процесс (внутри — свой httpx.Client)."""
global _user_provider
if _user_provider is None:
config = GAuthConfig(
base_url=settings.gauth_base_url,
client_id=settings.gauth_client_id,
client_secret=settings.gauth_client_secret,
redirect_uri=settings.gauth_redirect_uri,
)
_user_provider = HttpRuntimeUserProvider(config)
return _user_provider
def get_current_user(
request: Request,
settings: Settings = Depends(get_settings),
) -> AuthenticatedUser:
"""Валидирует Bearer-токен через userinfo gnexus-auth."""
auth = request.headers.get("Authorization", "")
if not auth.startswith("Bearer "):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Требуется Bearer-токен gnexus-auth",
headers={"WWW-Authenticate": "Bearer"},
)
try:
# TODO: короткий TTL-кэш userinfo по токену (до 60 c) — после появления нагрузки.
return _get_user_provider(settings).fetch_user(auth.removeprefix("Bearer "))
except Exception:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Токен невалиден или истёк",
headers={"WWW-Authenticate": "Bearer"},
) from None
def require_admin(
user: AuthenticatedUser = Depends(get_current_user),
) -> AuthenticatedUser:
"""Гейт админки: system_role admin или выше, остальным — 403."""
if (user.system_role or "") not in ADMIN_ROLES:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Недостаточно прав: админ-панель доступна роли admin и выше",
)
return user