如何根据客户端请求将Superset指向不同数据库
实现Superset按客户端域名路由至对应客户数据库的方案
核心思路
Superset原生不支持按域名路由数据源,但可以通过自定义Django中间件+重载数据源获取逻辑,在单个应用进程内实现请求域名到客户数据库的映射,满足企业客户数据隔离的需求。
具体实现步骤
1. 编写域名解析中间件
创建自定义中间件,在请求进入Superset核心逻辑前,解析请求的Host头,将域名映射到对应的数据库ID,并绑定到请求上下文:
# middleware.py from django.http import HttpRequest class DomainRoutingMiddleware: def __init__(self, get_response): self.get_response = get_response # 域名-数据库ID映射,可从配置文件/数据库动态读取 self.domain_db_mapping = { "clientA.domain.com": 1, "clientB.domain.com": 2 } def __call__(self, request: HttpRequest): host = request.META.get("HTTP_HOST", "").split(":")[0] # 去掉端口号 request.client_db_id = self.domain_db_mapping.get(host) response = self.get_response(request) return response
将中间件添加到Superset的Django配置中,修改superset/config.py的MIDDLEWARE列表:
MIDDLEWARE = [ # 其他默认中间件... "your_project.middleware.DomainRoutingMiddleware", ]
2. 重载数据源获取逻辑
通过自定义安全管理器,重载Superset获取数据库的核心方法,优先使用请求上下文传递的client_db_id:
# security.py from superset.security import SupersetSecurityManager from superset.models.core import Database from flask import request class CustomDomainSecurityManager(SupersetSecurityManager): def get_database(self, database_id=None): # 优先使用请求上下文的数据库ID client_db_id = getattr(request, "client_db_id", None) if client_db_id: target_db = Database.query.get(client_db_id) if target_db: return target_db # 回退到默认逻辑 return super().get_database(database_id)
在config.py中指定自定义安全管理器:
CUSTOM_SECURITY_MANAGER = "your_project.security.CustomDomainSecurityManager"
3. 配置域名与数据库映射
- 在Superset后台为每个企业客户创建独立的数据库连接,记录每个数据库的ID(可在数据库编辑页面的URL中查看,如
/database/edit/1中的1)。 - 更新中间件中的
domain_db_mapping,将客户域名与对应数据库ID绑定;若需动态更新,可将映射存储到数据库或配置中心,在中间件中实时读取。
4. 处理异常场景
在中间件中添加无匹配域名的处理逻辑,避免非法访问:
# 修改middleware.py的__call__方法 def __call__(self, request: HttpRequest): host = request.META.get("HTTP_HOST", "").split(":")[0] request.client_db_id = self.domain_db_mapping.get(host) if not request.client_db_id: # 返回403禁止访问或重定向到默认页面 from django.http import HttpResponseForbidden return HttpResponseForbidden("Invalid client domain") response = self.get_response(request) return response
关键注意事项
- 请求上下文覆盖:确保所有涉及数据库查询的流程(如仪表盘加载、SQL查询)都能获取到请求上下文的
client_db_id;对于异步任务(如报表导出),需手动传递client_db_id到任务参数中。 - 权限加固:为每个客户的Superset用户配置仅能访问对应数据库的角色权限,防止恶意请求绕过域名路由逻辑。
- 测试验证:分别用不同域名发起请求,验证查询是否正确路由到对应数据库,同时测试无匹配域名的异常处理逻辑。
内容的提问来源于stack exchange,提问作者Ouroboros
相关产品推荐
相关产品推荐

