Initial commit
This commit is contained in:
46
backend/app/middleware/correlation_id.py
Normal file
46
backend/app/middleware/correlation_id.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Correlation ID Middleware - ServiceManagerWeb
|
||||
|
||||
Middleware para rastrear requests con correlation ID
|
||||
"""
|
||||
|
||||
from fastapi import Request
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.responses import Response
|
||||
import uuid
|
||||
import structlog
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
class CorrelationIDMiddleware(BaseHTTPMiddleware):
|
||||
"""
|
||||
Middleware para manejar correlation IDs.
|
||||
|
||||
Extrae el correlation ID del header X-Correlation-ID o genera uno nuevo.
|
||||
Lo almacena en el estado de la request para uso en logs y responses.
|
||||
"""
|
||||
|
||||
async def dispatch(self, request: Request, call_next) -> Response:
|
||||
"""Process request and add correlation ID."""
|
||||
|
||||
# Extract or generate correlation ID
|
||||
correlation_id = request.headers.get("X-Correlation-ID")
|
||||
if not correlation_id:
|
||||
correlation_id = str(uuid.uuid4())
|
||||
|
||||
# Store in request state
|
||||
request.state.correlation_id = correlation_id
|
||||
|
||||
# Add to structlog context
|
||||
with structlog.contextvars.bound_contextvars(
|
||||
correlation_id=correlation_id,
|
||||
path=request.url.path,
|
||||
method=request.method
|
||||
):
|
||||
response = await call_next(request)
|
||||
|
||||
# Add correlation ID to response headers
|
||||
response.headers["X-Correlation-ID"] = correlation_id
|
||||
|
||||
return response
|
||||
72
backend/app/middleware/tenant.py
Normal file
72
backend/app/middleware/tenant.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
Tenant Middleware - ServiceManagerWeb
|
||||
|
||||
Middleware para manejo de multi-tenancy
|
||||
"""
|
||||
|
||||
from fastapi import Request, HTTPException, status
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.responses import Response
|
||||
import structlog
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
class TenantMiddleware(BaseHTTPMiddleware):
|
||||
"""
|
||||
Middleware para extraer y validar información del tenant.
|
||||
|
||||
Extrae el tenant_id del header X-Tenant-ID y lo almacena
|
||||
en el estado de la request para uso posterior.
|
||||
"""
|
||||
|
||||
# Rutas que no requieren tenant
|
||||
EXCLUDED_PATHS = {
|
||||
"/health",
|
||||
"/",
|
||||
"/v1/auth/login",
|
||||
"/docs",
|
||||
"/openapi.json",
|
||||
"/redoc"
|
||||
}
|
||||
|
||||
async def dispatch(self, request: Request, call_next) -> Response:
|
||||
"""Process request and add tenant information."""
|
||||
|
||||
# Skip tenant validation for excluded paths
|
||||
if request.url.path in self.EXCLUDED_PATHS or request.url.path.startswith("/docs"):
|
||||
return await call_next(request)
|
||||
|
||||
# Extract tenant from header
|
||||
tenant_id = request.headers.get("X-Tenant-ID")
|
||||
tenant_slug = request.headers.get("X-Tenant-Slug")
|
||||
|
||||
# For now, we'll be more permissive in development
|
||||
# In production, tenant should be strictly required
|
||||
if not tenant_id and not tenant_slug:
|
||||
logger.warning(
|
||||
"Request without tenant information",
|
||||
path=request.url.path,
|
||||
method=request.method
|
||||
)
|
||||
# For now, continue without tenant for development
|
||||
# raise HTTPException(
|
||||
# status_code=status.HTTP_400_BAD_REQUEST,
|
||||
# detail="Tenant information required (X-Tenant-ID or X-Tenant-Slug header)"
|
||||
# )
|
||||
|
||||
# Store tenant info in request state
|
||||
request.state.tenant_id = tenant_id
|
||||
request.state.tenant_slug = tenant_slug
|
||||
|
||||
# TODO: Validate tenant exists and is active
|
||||
# This would involve a database query which we'll implement later
|
||||
|
||||
logger.debug(
|
||||
"Tenant middleware processed",
|
||||
tenant_id=tenant_id,
|
||||
tenant_slug=tenant_slug,
|
||||
path=request.url.path
|
||||
)
|
||||
|
||||
return await call_next(request)
|
||||
Reference in New Issue
Block a user