feat: production deployment - full update with providers, admin, glossaries, pricing, tests
Major changes across backend, frontend, infrastructure: - Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud) - Admin panel: user management, pricing, settings - Glossary system with CSV import/export - Subscription and tier quota management - Security hardening (rate limiting, API key auth, path traversal fixes) - Docker compose for dev, prod, and IONOS deployment - Alembic migrations for new tables - Frontend: dashboard, pricing page, landing page, i18n (en/fr) - Test suite and verification scripts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ API Key Authentication Middleware
|
||||
|
||||
Provides reusable dependencies for API key authentication across all endpoints.
|
||||
Story 3.4: Authentification API via X-API-Key
|
||||
Story 6.4: Bind user_id to structlog context when user is resolved (logs include user_id).
|
||||
"""
|
||||
|
||||
from typing import Optional, Any, Union
|
||||
@@ -69,8 +70,11 @@ async def get_user_from_api_key(
|
||||
|
||||
try:
|
||||
from services.auth_service import get_user_by_api_key
|
||||
|
||||
from core.logging import bind_request_context
|
||||
|
||||
user = get_user_by_api_key(x_api_key)
|
||||
if user is not None:
|
||||
bind_request_context(user_id=str(getattr(user, "id", user)))
|
||||
return user
|
||||
|
||||
except ValueError as e:
|
||||
@@ -125,21 +129,26 @@ async def get_authenticated_user_optional(
|
||||
try:
|
||||
user = await get_user_from_api_key(x_api_key)
|
||||
if user:
|
||||
from core.logging import bind_request_context
|
||||
bind_request_context(user_id=str(getattr(user, "id", user)))
|
||||
return user
|
||||
except APIKeyError:
|
||||
# Invalid API key, fall through to JWT
|
||||
pass
|
||||
|
||||
|
||||
# Fall back to JWT
|
||||
if credentials:
|
||||
try:
|
||||
from routes.auth_routes import get_current_user
|
||||
|
||||
|
||||
user = await get_current_user(credentials)
|
||||
if user:
|
||||
from core.logging import bind_request_context
|
||||
bind_request_context(user_id=str(getattr(user, "id", user)))
|
||||
return user
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -167,20 +176,25 @@ async def get_authenticated_user(
|
||||
# get_user_from_api_key will raise APIKeyError for invalid keys
|
||||
user = await get_user_from_api_key(x_api_key)
|
||||
if user:
|
||||
from core.logging import bind_request_context
|
||||
bind_request_context(user_id=str(getattr(user, "id", user)))
|
||||
return user
|
||||
# Should not reach here - get_user_from_api_key returns None only if no key provided
|
||||
raise APIKeyError("INVALID_API_KEY", "Clé API invalide ou non reconnue.")
|
||||
|
||||
|
||||
# Fall back to JWT
|
||||
if credentials:
|
||||
try:
|
||||
from routes.auth_routes import get_current_user
|
||||
|
||||
|
||||
user = await get_current_user(credentials)
|
||||
if user:
|
||||
from core.logging import bind_request_context
|
||||
bind_request_context(user_id=str(getattr(user, "id", user)))
|
||||
return user
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -198,10 +212,12 @@ async def require_authenticated_user(
|
||||
User object (guaranteed to be authenticated)
|
||||
"""
|
||||
user = await get_authenticated_user(credentials, x_api_key)
|
||||
|
||||
|
||||
if not user:
|
||||
raise APIKeyError("MISSING_API_KEY", "Authentification requise. Utilisez X-API-Key ou Authorization: Bearer.")
|
||||
|
||||
|
||||
from core.logging import bind_request_context
|
||||
bind_request_context(user_id=str(getattr(user, "id", user)))
|
||||
return user
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user