You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据客户端请求将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 15:45:14