feat(multitenancy): Add TenantHeaderMiddleware to support centralized API with tenant switching
- Implemented TenantHeaderMiddleware to switch the database tenant schema based on the 'X-Business-Subdomain' request header. - This allows API requests directed to the centralized 'api' subdomain (e.g., api.lvh.me) to correctly access tenant-specific data when the header is present. - Registered the middleware in multitenancy settings after TenantMainMiddleware.
This commit is contained in:
@@ -94,6 +94,7 @@ MIDDLEWARE = [
|
|||||||
|
|
||||||
# 1. Tenant resolution
|
# 1. Tenant resolution
|
||||||
'django_tenants.middleware.main.TenantMainMiddleware',
|
'django_tenants.middleware.main.TenantMainMiddleware',
|
||||||
|
'core.middleware.TenantHeaderMiddleware', # Support tenant switching via header
|
||||||
|
|
||||||
# 2. Security middleware
|
# 2. Security middleware
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
|||||||
@@ -8,11 +8,35 @@ import json
|
|||||||
from django.utils.deprecation import MiddlewareMixin
|
from django.utils.deprecation import MiddlewareMixin
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
|
from django_tenants.utils import get_tenant_model
|
||||||
|
|
||||||
logger = logging.getLogger('smoothschedule.security.masquerade')
|
logger = logging.getLogger('smoothschedule.security.masquerade')
|
||||||
sandbox_logger = logging.getLogger('smoothschedule.sandbox')
|
sandbox_logger = logging.getLogger('smoothschedule.sandbox')
|
||||||
|
|
||||||
|
|
||||||
|
class TenantHeaderMiddleware(MiddlewareMixin):
|
||||||
|
"""
|
||||||
|
Middleware to switch tenant based on 'X-Business-Subdomain' header.
|
||||||
|
Allows centralized API domain (e.g., api.smoothschedule.com) to serve tenant-specific data.
|
||||||
|
Must be placed AFTER TenantMainMiddleware.
|
||||||
|
"""
|
||||||
|
def process_request(self, request):
|
||||||
|
# Check for header
|
||||||
|
subdomain = request.META.get('HTTP_X_BUSINESS_SUBDOMAIN')
|
||||||
|
if subdomain:
|
||||||
|
Tenant = get_tenant_model()
|
||||||
|
try:
|
||||||
|
tenant = Tenant.objects.get(schema_name=subdomain)
|
||||||
|
# Only switch if different from current tenant (which might be 'public')
|
||||||
|
if request.tenant.schema_name != tenant.schema_name:
|
||||||
|
request.tenant = tenant
|
||||||
|
connection.set_tenant(request.tenant)
|
||||||
|
# sandbox_logger.debug(f"Switched to tenant '{subdomain}' via header")
|
||||||
|
except Tenant.DoesNotExist:
|
||||||
|
# Invalid subdomain in header - ignore or could raise 400
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SandboxModeMiddleware(MiddlewareMixin):
|
class SandboxModeMiddleware(MiddlewareMixin):
|
||||||
"""
|
"""
|
||||||
Middleware to switch between live and sandbox schemas based on:
|
Middleware to switch between live and sandbox schemas based on:
|
||||||
|
|||||||
Reference in New Issue
Block a user