无法在Apache Superset中嵌入Dash WSGI应用iframe问题求助
问题描述
前同事开发了基于Apache Superset与Dash WSGI的内部数据可视化工具,现在尝试在Superset中通过HTML iframe嵌入该Dash应用时无内容显示,但本地创建简单HTML文件调用iframe却能正常工作。两者均部署在NGINX后实现HTTPS转发,相关配置如下:
Apache Superset 配置
superset_config.py(不含密钥、SQL URI及服务器信息)
DISPLAY_MAX_ROW = 1000 ROW_LIMIT = 1000000 SQL_MAX_ROW = 1000000 # Flask-WTF flag for CSRF WTF_CSRF_ENABLED = False # Add endpoints that need to be exempt from CSRF protection WTF_CSRF_EXEMPT_LIST = [] # A CSRF token that expires in 1 year WTF_CSRF_TIME_LIMIT = 60 * 60 * 24 * 365 # Set this API key to enable Mapbox visualizations MAPBOX_API_KEY = '' FEATURE_FLAGS = { "ALERT_REPORTS": True, "DASHBOARD_CROSS_FILTERS": True, "DASHBOARD_FILTERS_EXPERIMENTAL": True, "DASHBOARD_NATIVE_FILTERS_SET": True, "DASHBOARD_NATIVE_FILTERS": True, "DASHBOARD_RBAC": True, "DYNAMIC_PLUGINS": True, "ENABLE_TEMPLATE_PROCESSING": True } ENABLE_CORS = True CORS_OPTIONS = { 'allow_headers': ['*'], 'origins': ['*'], 'resources': ['*'] } EXPLORE_FORM_DATA_CACHE_CONFIG = { 'CACHE_TYPE': 'RedisCache', 'CACHE_DEFAULT_TIMEOUT': 86400, 'CACHE_KEY_PREFIX': 'EXPLORE_FORM_DATA_CACHE_CONFIG', 'CACHE_REDIS_URL': 'redis://localhost:6379/0' } FILTER_STATE_CACHE_CONFIG = { 'CACHE_TYPE': 'RedisCache', 'CACHE_DEFAULT_TIMEOUT': 86400, 'CACHE_KEY_PREFIX': 'FILTER_STATE_CACHE_CONFIG', 'CACHE_REDIS_URL': 'redis://localhost:6379/0' } TALISMAN_ENABLED = True TALISMAN_CONFIG = { "content_security_policy": { "img-src": [ "'self'", "data:" ], "connect-src": [ "'self'", "https://api.mapbox.com", "https://events.mapbox.com", ], "style-src": [ "'self'", "'unsafe-inline'" ], "frame-ancestors": [ "'self'" ] }, "content_security_policy_nonce_in": [ "script-src" ], "force_https": True }
Superset的NGINX配置(隐藏证书及服务器信息)
server { listen 443 ssl; listen [::]:443 ssl; location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; } }
Dash WSGI 配置
代码
from dash import Dash, dcc, html, Input, Output, callback import apps import os import pkgutil import re superset_colors = {"blue" : "rgb(32,167,201)"} app = Dash(__name__, suppress_callback_exceptions=True, title = "IMEDA") server = app.server app.layout = html.Div([ dcc.Location(id='url', refresh=False), html.Div(id='page-content') ]) @callback(Output('page-content', 'children'), Input('url', 'pathname')) def display_page(pathname): address = re.search(r"/apps/(.*)", pathname) modules = [a.name for a in pkgutil.iter_modules(apps.__path__)] if address is not None: dashboard = address.group(1) if address is None or dashboard not in modules: return '404' else: return getattr(apps, dashboard).layout if __name__ == '__main__': app.run(debug=True)
Dash WSGI的NGINX配置
server { listen 8443 ssl; listen [::]:8443 ssl; location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; } }
已尝试的解决步骤
- 调整superset_config.py和app.py中的CSP设置
- 调整Superset和Dash的NGINX HTTP头配置
- 本地创建HTML文件调用iframe,能正常工作
解决方案
问题核心在于Superset的CSP(内容安全策略)限制了iframe的嵌入来源,同时Dash应用未配置允许被Superset域名嵌入的响应头,以下是具体修复步骤:
1. 修改Superset的TALISMAN CSP配置
在superset_config.py的TALISMAN_CONFIG中,新增frame-src并添加Dash应用的完整HTTPS地址,同时更新connect-src允许Dash的API请求:
"content_security_policy": { "img-src": [ "'self'", "data:" ], "connect-src": [ "'self'", "https://api.mapbox.com", "https://events.mapbox.com", "https://your-dash-domain:8443" # 替换为你的Dash应用域名+端口 ], "style-src": [ "'self'", "'unsafe-inline'" ], "frame-src": [ "'self'", "https://your-dash-domain:8443" # 允许加载Dash的iframe内容 ], "frame-ancestors": [ "'self'" ] },
2. 配置Dash应用的嵌入允许头
在Dash代码中添加响应头,允许Superset域名嵌入:
from flask import Flask # 创建Dash app之后添加 server = app.server @server.after_request def add_embedding_headers(response): # 替换为你的Superset域名,如https://your-superset-domain response.headers['Content-Security-Policy'] = 'frame-ancestors https://your-superset-domain' return response
3. 加固NGINX配置(可选)
在Dash的NGINX配置中显式设置允许嵌入的头,避免被默认配置覆盖:
location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 确保允许Superset嵌入 proxy_hide_header X-Frame-Options; add_header Content-Security-Policy "frame-ancestors https://your-superset-domain"; proxy_redirect off; }
4. 重启服务
修改配置后,依次重启Superset、Dash应用及NGINX,确保配置生效。
内容的提问来源于stack exchange,提问作者imeda
相关产品推荐
相关产品推荐

