This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Benjamin Admin 21a844cb8a fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.

This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).

Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 09:51:32 +01:00

97 lines
2.7 KiB
Python

"""
Auth Middleware für LLM Gateway.
Unterstützt:
- API Key Auth (X-API-Key Header oder Authorization Bearer)
- JWT Token Auth (vom Consent Service)
"""
import logging
from typing import Optional
from fastapi import HTTPException, Header, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
from ..config import get_config
logger = logging.getLogger(__name__)
security = HTTPBearer(auto_error=False)
async def verify_api_key(
x_api_key: Optional[str] = Header(None, alias="X-API-Key"),
authorization: Optional[HTTPAuthorizationCredentials] = Depends(security),
) -> str:
"""
Verifiziert den API Key oder JWT Token.
Akzeptiert:
- X-API-Key Header
- Authorization: Bearer <token>
Returns:
str: User ID oder "api_key" bei API Key Auth
"""
config = get_config()
# 1. Prüfe X-API-Key Header
if x_api_key:
if x_api_key in config.api_keys:
return "api_key"
logger.warning(f"Invalid API key attempted")
raise HTTPException(
status_code=401,
detail={"error": "unauthorized", "message": "Invalid API key"},
)
# 2. Prüfe Authorization Header
if authorization:
token = authorization.credentials
# Prüfe ob es ein API Key ist
if token in config.api_keys:
return "api_key"
# Versuche JWT zu dekodieren
if config.jwt_secret:
try:
payload = jwt.decode(
token,
config.jwt_secret,
algorithms=["HS256"],
)
user_id = payload.get("user_id") or payload.get("sub")
if user_id:
return str(user_id)
except jwt.ExpiredSignatureError:
raise HTTPException(
status_code=401,
detail={"error": "token_expired", "message": "Token has expired"},
)
except jwt.InvalidTokenError as e:
logger.warning(f"Invalid JWT token: {e}")
raise HTTPException(
status_code=401,
detail={"error": "invalid_token", "message": "Invalid token"},
)
# 3. In Development Mode ohne Auth erlauben
if config.debug:
logger.warning("Auth bypassed in debug mode")
return "debug_user"
# 4. Keine gültige Auth gefunden
raise HTTPException(
status_code=401,
detail={
"error": "unauthorized",
"message": "API key or valid token required",
},
)
def get_current_user_id(user_id: str = Depends(verify_api_key)) -> str:
"""Dependency um die aktuelle User ID zu bekommen."""
return user_id