This commit is contained in:
Mikan
2026-06-20 22:21:47 +03:00
parent 8514c63ec6
commit 0e1616d51c
12 changed files with 206 additions and 35 deletions

View File

@@ -1,11 +1,17 @@
"""Shared API dependencies: current user, admin guard, db session, settings."""
"""Shared API dependencies: current user, admin guard, db session, settings.
Token resolution order:
1. `Authorization: Bearer <jwt>` header (preferred).
2. `?access_token=<jwt>` query parameter (fallback for SSE — EventSource cannot
set custom headers).
"""
from __future__ import annotations
import uuid
from typing import Any
from fastapi import Depends, HTTPException, status
from fastapi import Depends, HTTPException, Query, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
@@ -20,16 +26,29 @@ _bearer = HTTPBearer(auto_error=False)
async def get_current_user(
creds: HTTPAuthorizationCredentials | None = Depends(_bearer),
access_token: str | None = Query(default=None, description="JWT access token (fallback for SSE)"),
db: AsyncSession = Depends(get_db),
) -> User:
"""Resolve the JWT bearer token to a User row.
Accepts the token either in the `Authorization: Bearer <jwt>` header
or as the `?access_token=<jwt>` query parameter (the latter is needed
because native `EventSource` cannot send custom headers, and the
frontend SSE client passes the token via query string).
Raises 401 on missing/invalid/expired token.
"""
if creds is None or creds.scheme.lower() != "bearer":
raw_token: str | None = None
if creds is not None and creds.scheme.lower() == "bearer":
raw_token = creds.credentials
elif access_token:
raw_token = access_token
if not raw_token:
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Missing bearer token")
try:
payload = decode_token(creds.credentials)
payload = decode_token(raw_token)
except Exception as e: # noqa: BLE001
raise HTTPException(status.HTTP_401_UNAUTHORIZED, f"Invalid token: {e}")
if payload.get("type") != "access":