十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Metabase Guest Embedding 完全指南:无 SSO 的 JWT 嵌入式仪表板与问题嵌入实战

Metabase Guest Embedding 完全指南:无 SSO 的 JWT 嵌入式仪表板与问题嵌入实战 Metabase Guest Embedding 完全指南无 SSO 的 JWT 嵌入式仪表板与问题嵌入实战【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabaseGuest Embedding访客嵌入是 Metabase 提供的一种嵌入式认证方案你无需为每个查看图表/仪表板的访客创建 Metabase 账号只需在自己的应用服务端用共享密钥签发 JWT即可把问题Question、仪表板Dashboard以 Web Component 的形式嵌入到你的网站中。本文基于当前仓库的官方文档与源码完整讲解从开启功能、生成嵌入代码、配置三类参数Disabled / Editable / Locked到 JWT 刷新端点guestEmbedProviderUri、锁定参数进阶用法与安全运维的方方面面读完即可在自托管或商业版 Metabase 上落地一套不依赖 SSO 的嵌入式分析方案。认识 Guest Embed认证方式与数据新鲜度Guest访客指的是认证方式Metabase不会为每个查看嵌入内容的人创建会话。它有两层关键含义认证与数据新鲜度无关Guest Embed 中的仪表板与图表始终展示数据库中的实时数据不存在快照或缓存副本不使用 SSO 依然安全Metabase 只有在请求携带一个使用你与 Metabase 共享的密钥签名过的 JWT时才会加载嵌入内容。JWT 中除了签名本身还包含要加载资源的引用如嵌入项 ID以及任意参数值。如果要针对特定人群或分组限制 Guest Embed 中的数据官方推荐使用 锁定参数Locked Parameters 机制详见下文。从源码结构看Metabase 的嵌入体系由多个模块协同metabase.embedding.settings嵌入相关设置、metabase.embedding.jwtJWT 解析与验签、metabase.embedding-rest.api.embed/api/embed/*端点以及前端 SDK 目录 frontend/src/metabase/embedding/embedding-iframe-sdk。本文涉及的所有行为都对应着这些模块中的真实实现。在 Metabase 中开启 Guest Embedding开启入口因 Metabase 版本/版本类型而异OSS开源版Admin管理设置 EmbeddingStarter / Pro / EnterpriseAdmin Embedding Guest embeds在页面中打开Enable guest embeds开关即可。这一开关在源码中对应enable-embedding-simple设置见 src/metabase/embedding/settings.clj。值得注意的底层细节开启后如果embedding-secret-key尚为空Metabase 会自动调用secure-hex 32生成一个 256-bit 的随机密钥开关状态变化会通过 Snowplow 记录embed_share事件并统计当前已嵌入的问题数与仪表板数该开关支持通过环境变量MB_ENABLE_EMBEDDING_SIMPLE配置从 0.51.0 起旧的MB_ENABLE_EMBEDDING已废弃同时设置新旧变量会在启动时报错。创建 Guest Embed 的完整流程Metabase 提供了一个可视化向导Embedding 向导来生成可用的嵌入代码。官方文档给出的操作步骤如下打开你想要嵌入到网站中的对象问题或仪表板。你也可以按Ctrl/Cmd K打开命令面板输入 New embed 快速进入点击Share分享图标选择Embed在Authentication认证方式下选择Guest可选定制嵌入的外观可选设置每个参数的可见性点击Publish发布复制向导生成的代码片段添加到你的应用中。向导生成的代码分为客户端与服务端两部分下面逐一拆解。向导生成代码详解客户端与服务端客户端代码加载脚本与 Web Component在你的 HTML 中引入嵌入脚本并配置全局配置对象script defer srcYOUR_METABASE_URL/app/embed.js/script script window.metabaseConfig { isGuest: true, instanceUrl: YOUR_METABASE_URL, // Optional. Set this if you want the embed to fetch a fresh JWT // when the current one expires. See Refreshing the JWT below. // guestEmbedProviderUri: /your/apps/endpoint, }; /script然后为要嵌入的对象添加对应的 Web Component!-- For dashboards -- metabase-dashboard tokenYOUR_JWT_TOKEN with-titletrue with-downloadsfalse initial-parameters{category:[Gizmo]} /metabase-dashboard !-- For questions -- metabase-question tokenYOUR_JWT_TOKEN/metabase-question重要安全提醒不要把写死的 JWT 留在 HTML 里。Token 会过期嵌入随后就会失效。正确的做法有两种要么在你的服务端为每次页面加载签署一个新鲜 Token 并渲染进token属性要么配置guestEmbedProviderUri让嵌入组件自己获取并刷新 Token。服务端代码签名 JWTNode.js 示例你的服务器负责生成已签名的 JWT 来认证嵌入请求。官方文档给出的 Node.js 示例const jwt require(jsonwebtoken); const METABASE_SECRET_KEY YOUR_METABASE_SECRET_KEY; const payload { resource: { dashboard: 10 }, // or { question: 5 } for questions params: {}, exp: Math.round(Date.now() / 1000) 10 * 60, // 10 minute expiration }; const token jwt.sign(payload, METABASE_SECRET_KEY);把YOUR_METABASE_SECRET_KEY替换成你的 embedding secret key。示例中使用的是顺序 ID即对象 URL 中的数字在 Pro 和 Enterprise 版本中你也可以使用 实体 IDEntity IDs它在从一个 Metabase 序列化到另一个例如从 staging 到 production时保持不变。关于密钥的格式源码 src/metabase/embedding/settings.clj 中给出了硬性校验secret key 必须是十六进制编码的 256-bit 密钥即一个 64 字符的字符串否则设置会被拒绝报错信息原文Invalid embedding-secret-key! Secret key must be a hexadecimal-encoded 256-bit key (i.e., a 64-character string).。此外该密钥在数据库中的存储采用:when-encryption-key-set加密策略仅管理员可见且不会出现在审计日志的值里。组件属性参考你可以通过设置不同属性来开启/关闭 UI 能力。常用属性如下属性说明token必填。来自你服务端的已签名 JWT。with-title显示或隐藏标题。取值true或false。with-downloads*启用或禁用下载。取值true或false。initial-parameters初始参数值的 JSON 字符串非受控。示例{category:[Gizmo]}。详见 Modular embedding 参数。parameters参数值的 JSON 字符串受控。示例{category:[Gizmo]}。详见 Modular embedding 参数。auto-refresh-interval仅仪表板。自动刷新间隔秒。custom-context转发给你的guestEmbedProviderUri端点作为customContext字段。可以是字符串如gadgets-tab也可以是像initial-parameters那样的 JSON 字符串化对象如{tab:gadgets,region:us-east}。* 禁用下载仅在 Pro 与 Enterprise 版本可用。不同嵌入对象可用的属性不同Guest Embed 的选项比 SSO 嵌入更少。完整属性清单请参考 仪表板组件参考 与 问题组件参考。定制 Guest Embed 的外观Guest Embed 可用的外观设置取决于你的 Metabase 版本OSS/Starter 只能选择浅色或深色主题Pro/Enterprise 则提供细粒度定制选项字体、色彩、Logo 等详见 Appearance外观。配置参数Disabled / Editable / Locked参数默认是Disabled状态此时对最终用户完全隐藏且不可设置。你可以把每个参数配置为三种状态之一Disabled禁用对最终用户隐藏不可设置。这是默认值Editable可编辑最终用户可以看到并修改参数值Locked锁定对最终用户隐藏由你的服务器而非最终用户通过 JWT 设置。配置参数的步骤打开你要嵌入的问题或仪表板点击Share图标选择Embed在Parameters参数下为每个参数选择可见性选项并可选设置默认值点击Publish。这一设计在服务端对应embedding_params即:embedding_params字段。源码 src/metabase/embedding_rest/api/common.clj 的check-params-are-allowed函数完整实现了三种状态的校验逻辑disabledJWT 和 URL 查询参数都不允许携带该参数否则返回400 Youre not allowed to specify a value for param.enabledJWT或URL 可指定但两者不能同时出现否则返回400 You cant specify a value for param if its already set in the JWT.lockedJWT必须包含该参数否则报You must specify a value for param in the JWT.且 URL 中不允许再指定。Editable可编辑参数设置为 Editable 后你可以为过滤器设置默认值但用户在查看问题或仪表板时可以修改这些值。服务端代码传入空的params对象即可// you will need to install via npm install jsonwebtoken or in your package.json const jwt require(jsonwebtoken); const METABASE_SECRET_KEY YOUR_METABASE_SECRET_KEY; const payload { resource: { dashboard: 10 }, params: {}, exp: Math.round(Date.now() / 1000) 10 * 60, // 10 minute expiration }; const token jwt.sign(payload, METABASE_SECRET_KEY);客户端代码用initial-parameters在客户端设置默认参数script defer srcYOUR_METABASE_URL/app/embed.js/script script function defineMetabaseConfig(config) { window.metabaseConfig config; } /script script defineMetabaseConfig({ isGuest: true, instanceUrl: YOUR_METABASE_URL, }); /script !-- This token is a placeholder. Dont paste a fixed JWT into your HTML: sign a fresh one on your server for each page load, or use guestEmbedProviderUri. -- metabase-dashboard tokenYOUR SIGNED TOKEN with-titletrue with-downloadsfalse initial-parameters{category:[Doohickey,Gizmo]} /metabase-dashboard受控参数parameters属性的文档见 Modular embedding 参数。Locked锁定参数锁定参数让你在不把过滤器暴露给最终用户的前提下过滤数据。它非常适合按观看者身份限制数据——例如让每个客户只能看到自己的数据。使用锁定参数需要三步在嵌入设置中把参数设为Locked在服务端把参数值写进 JWT发布Publish该对象。下面是锁定category参数时 Metabase 生成的示例代码。服务端代码Node.js——在服务端设置锁定参数将其放进 token// Install via npm install jsonwebtoken const jwt require(jsonwebtoken); const METABASE_SECRET_KEY YOUR_METABASE_SECRET_KEY; const payload { resource: { dashboard: 10 }, params: { category: [Gadget], // Set the locked parameter value to Gadget }, exp: Math.round(Date.now() / 1000) 10 * 60, // 10 minute expiration }; const token jwt.sign(payload, METABASE_SECRET_KEY);客户端代码HTML——参数完全由 JWT 决定script defer srcYOUR_METABASE_URL/app/embed.js/script script window.metabaseConfig { isGuest: true, // Must be set to guest instanceUrl: YOUR_METABASE_URL, }; /script !-- This token is a placeholder. Dont paste a fixed JWT into your HTML: sign a fresh one on your server for each page load, or use guestEmbedProviderUri. -- metabase-dashboard tokenYOUR_JWT_TOKEN with-titletrue with-downloadsfalse /metabase-dashboard最终用户看不到 category 过滤器但仪表板只会展示 Gadget 类别的数据或你在签名 JWT 的params对象中传给category数组的任何值。更新锁定参数的进阶规则JWT 必须包含所有锁定参数一旦你发布了带锁定参数的问题或仪表板签名 JWT 时必须在params对象中包含该锁定参数的名字。如果漏掉Metabase 会拒绝请求并记录日志You must specify a value for :parameter-name in the JWT。例如锁定参数是category报错会显示为You must specify a value for :category in the JWT。这条错误信息正对应上文源码中check-params-are-allowed对locked状态的校验(api/check (some? (get token-values param)) [400 (tru You must specify a value for {0} in the JWT. (keyword param))])。传入空数组以关闭锁定参数如果某个 Token 不希望应用锁定过滤可以给该参数传空数组[]const payload { resource: { dashboard: 10 }, params: { category: [], // locked filter is bypassed for this token }, exp: Math.round(Date.now() / 1000) 10 * 60, };这在你想跨上下文复用同一个仪表板/问题、并在某些场景下有条件地跳过锁定过滤器时非常有用。过滤器名称必须与锁定参数名匹配如果你重命名了作为锁定参数使用的仪表板过滤器需要同步更新 JWTparams对象中对应的 key。不过连接到 SQL 变量 的锁定参数无需在服务端改名。多个锁定参数 / 多值传递JWT 中锁定参数的值必须与过滤器值完全一致。设置多个锁定参数、或给单个锁定参数传多个值的最佳实践是在嵌入向导的Preview locked parameters下挑选一个过滤器值然后复制 Metabase 生成的对应服务端代码。多个锁定参数之间按AND组合而非 OR。如果某个 Token 只想应用其中一部分锁定参数请给其余参数传[]见上文传入空数组。锁定参数会限制其他可编辑参数的候选值由于锁定参数会在结果展示之前过滤数据它同时也会限制同一对象上任何可编辑过滤器部件的候选值。举例你嵌入了一个带 State 和 City 两个过滤器的仪表板。如果把 State 锁定为 Vermont那么 City 过滤器的下拉框里只会出现 Vermont 的市。你不需要显式地把两个过滤器串联起来——它们会自动表现得像 链接过滤器。含 SQL 问题的仪表板锁定参数只能传单一值如果锁定参数连接的仪表板过滤器又连接到了仪表板上的SQL 问题那么你在 JWT 中只能为该锁定参数传单个值。例如仪表板过滤器叫 Breakfast候选值有 Hash browns、Muffin、Waffles而该过滤器连接了仪表板上任意一个SQL 问题那么作为锁定参数值时你只能从中选一个传入。用锁定参数驱动你自建的自定义过滤部件因为 Metabase 不会渲染锁定参数对应的过滤器部件你可以用它来驱动自己构建的自定义过滤部件。自建过滤部件的常见动机让部件与你应用的外观风格保持一致加入自定义逻辑比如记住最近使用的值在应用的不同位置以不同方式复用同一个仪表板。例如一个销售仪表板在一个位置按 region 锁定在另一个位置按 team 锁定。当最终用户在你的自定义部件中改了值时在服务端用更新后的params重新签名一个新的 JWT并替换到 Web Component 的token属性上嵌入内容就会用新的锁定值重新请求数据。针对这种流程建议在组件上预渲染一个初始 Token而不是让guestEmbedProviderUri提供第一个 Token。因为一个没有 Token 启动的嵌入会在加载时从你的端点获取一个 Token而这个 Token 会覆盖你的部件刚刚设置的值。从服务器刷新 / 初始化 JWTguestEmbedProviderUri你为 Guest Embed 签发的 JWT 带有过期时间exp。一旦过期嵌入将无法加载新数据且查看者已做的过滤器选择会在下一次请求时重置。为了让嵌入不刷新页面也能持续工作可以在你的服务器上配置一个 guest token 端点按需签发新 JWT。该端点可服务于两种流程刷新 Token当嵌入当前的 JWT 即将过期时嵌入组件会 POST 到你的端点获取新 JWT 并替换进去初始化 Token可选如果你完全不想在 HTML 中预渲染 JWT嵌入组件也可以在加载时调用同一端点获取第一个 JWT。在 guest embed 中设置端点地址在metabaseConfig中添加guestEmbedProviderUri值为你应用中一个端点的路径或完整 URLscript window.metabaseConfig { isGuest: true, instanceUrl: YOUR_METABASE_URL, guestEmbedProviderUri: /api/metabase-guest-token, }; /script当嵌入需要 Token 时它会向guestEmbedProviderUri发送一个POST请求请求体为 JSON并且会携带 cookie因此你可以用应用现有的会话体系来认证该请求。从前端实现看frontend/src/metabase/embedding/embedding-iframe-sdk/embed.tsSDK 会在请求 URL 上追加responsejson查询参数、使用fetch以POST方式调用该端点并解析返回中的jwt字段用于初始化或刷新 Token。请求体格式{ entityType: dashboard, entityId: 10, customContext: ... }字段说明entityTypedashboard或question。entityId正在被嵌入的仪表板或问题的 ID即你在组件上设置的 ID。customContext可选。你在custom-context属性上设置的字符串或对象。响应一个包含单个jwt字段的 JSON 对象{ jwt: YOUR_NEWLY_SIGNED_JWT }刷新流程Refresh flow在组件上预渲染一个初始 JWT就像普通 Guest Embed 一样同时配置guestEmbedProviderUri。JWT 过期时嵌入组件会调用你的端点获取新 Token 并替换。script window.metabaseConfig { isGuest: true, instanceUrl: YOUR_METABASE_URL, guestEmbedProviderUri: /api/metabase-guest-token, }; /script metabase-dashboard tokenYOUR_INITIAL_JWT/metabase-dashboard不在 HTML 中预渲染 JWT 的初始化方式如果你完全不想在 HTML 里渲染 JWT可以省略token属性改用dashboard-id或question-id。只要设置了guestEmbedProviderUri嵌入组件会在加载时调用该端点获取第一个 JWTmetabase-dashboard dashboard-id10/metabase-dashboard这样你可以把所有签发 Token 的逻辑统一放在服务器一处。端点示例Node.js / Expressconst jwt require(jsonwebtoken); const METABASE_SECRET_KEY YOUR_METABASE_SECRET_KEY; app.post(/api/metabase-guest-token, (req, res) { // Authenticate using your apps existing session. const user req.session?.user; if (!user) { return res.status(403).json({ error: Not signed in }); } const { entityType, entityId, customContext } req.body; // Authorize the request. The browser picks the entityType and entityId, so // check them against your own rule before signing for them. // This is just an example if (!userCanView(user, entityType, entityId)) { return res.status(403).json({ error: Not allowed }); } const payload { resource: { [entityType]: entityId }, params: paramsFor(user, customContext), exp: Math.round(Date.now() / 1000) 10 * 60, // 10 minute expiration }; res.json({ jwt: jwt.sign(payload, METABASE_SECRET_KEY) }); });因为嵌入的请求会携带你应用的会话 cookie你的端点可以对未登录你应用的访客拒绝签发 JWT返回403对某个访客不应看到的仪表板/问题拒绝签发 JWT。注意entityType与entityId来自浏览器一个不做校验就签名的端点会让任何已登录访客都能拿到任意已发布对象的 Token按访客计算不同的params即锁定的过滤值。发送自定义上下文custom-context当你在同一页面多次嵌入同一个仪表板/问题时可以用custom-context属性告诉端点正在请求 Token 的是哪一份拷贝。你传入的值会以customContext形式转发到端点。例如同一仪表板的两份拷贝分别限定不同类别metabase-dashboard dashboard-id10 custom-contextgadgets-tab /metabase-dashboard也可以传入 JSON 字符串化的对象嵌入组件会先解析再转发因此你的端点收到的是真实对象metabase-dashboard dashboard-id10 custom-context{tab:gadgets,region:us-east} /metabase-dashboard你的端点可以基于customContext设置不同的锁定参数例如function paramsFor(user, customContext) { switch (customContext) { case gadgets-tab: return { category: [Gadget] }; case doohickeys-tab: return { category: [Doohickey] }; default: return {}; } }Guest Embedding 的工作原理与请求链路源码级Guest Embed 使用 Web Componentmetabase-dashboard与metabase-question与你的 Metabase 实例通信。每次嵌入请求都需要一个用你的 secret key 签名的 JWT。一次完整的访问流程如下你的服务器生成一个包含资源 ID仪表板或问题以及任何锁定参数的签名 JWTWeb Component 把 Token 发送给 MetabaseMetabase 用你的 secret key 验证 JWT 签名验证通过后Metabase 返回嵌入内容如果你配置了 JWT 刷新嵌入组件会在当前 Token 过期后、下一次需要发起数据请求时从你的端点获取新 JWT——不是靠后台定时器。空闲的嵌入不会发起任何刷新请求。可选地嵌入组件也可以在加载时从端点获取第一个 JWT。整个过程无需刷新页面。从源码层面看这一链路在 src/metabase/embedding_rest/api/embed.clj 中实现核心端点包括GET /api/embed/card/:token获取问题Card的元数据GET /api/embed/card/:token/query执行问题查询并返回结果GET /api/embed/card/:token/query/:export-format以指定格式导出查询结果文件GET /api/embed/dashboard/:token获取仪表板GET /api/embed/dashboard/:token/dashcard/:dashcard-id/card/:card-id执行仪表板中某张卡片所属的查询以及对应的参数候选值、搜索、重映射remapping、透视pivot与地图瓦片tiles等端点。JWT 的验签逻辑在 src/metabase/embedding/jwt.clj 的unsign函数中它会先手动解析 JWT 头拒绝alg为none的 Token防止未签名伪造再用embedding-secret-key做签名验证并允许 60 秒的时钟偏移容差leeway任何验签失败都会以400状态返回。另外translate-token-ids会把 Token 中resource.question/resource.dashboard的实体 ID 翻译成内部card_id/dashboard_id——这正是实体 ID 在序列化迁移后保持不变能力的底层支撑。对于交互式过滤器你可以通过initial-parameters属性传入初始参数值当访客更改过滤器时Web Component 会自动处理更新。签名 JWT 使用你的 Metabase secret key 生成。secret key 是 Metabase 判断请求可信的依据。请注意这个密钥在所有 Guest Embed 之间共享谁拿到了它就能访问所有已嵌入的对象。运维与安全管理禁用某个问题/仪表板的嵌入访问可嵌入的问题或仪表板点击Share图标右上角带箭头的方框选择Embed选择Guest embedding点击Unpublish。管理员可以在Admin Embedding查看所有已嵌入项的列表Pro/Enterprise 版本请查看Guest embeds标签页。移除 Powered by Metabase 横幅Metabase 会在 OSS 与 Starter 版本的 Guest Embed图表和仪表板上添加 Powered by Metabase 横幅。要移除它需要升级到 Pro 或 Enterprise 版本。重新生成 embedding secret key你的 embedding secret key 用于为所有嵌入签发 JWT。进入Admin EmbeddingPro/Enterprise 版本查看Guest embeds标签页在Regenerate secret key下点击Regenerate key。该密钥在所有 Guest Embed 之间共享任何拿到它的人都可能访问所有已嵌入的对象请务必妥善保管。重新生成后需要同步更新你服务端代码中的密钥。其他注意事项仪表板自定义跳转Custom destinations限制在 Guest Embed 的仪表板中自定义跳转只能使用URL选项。外部 URL 会在新标签页/新窗口中打开。你可以在外部 URL 中透传过滤器值除非该过滤器是锁定状态。翻译嵌入内容要为嵌入设置界面语言在window.metabaseConfig中设置localescript window.metabaseConfig { isGuest: true, instanceUrl: YOUR_METABASE_URL, locale: es, }; /scriptlocale设置对所有模块化嵌入Guest、SSO 与 SDK都生效。Metabase 会自动翻译 UI 元素如菜单和按钮。若要同时翻译仪表板标题、过滤器标签等内容需要上传一份翻译词典。与 SDK 混合使用如果你正在使用 Modular Embedding SDK同时也想用 Guest 认证嵌入问题或仪表板你仍然需要先在 Metabase 中访问该对象并发布它。可以忽略向导生成的代码但为了让 Metabase 确认可以对外提供该对象发布是必须的。一个限制是你应用的每个页面只能使用一种认证类型。例如同一页面不能同时存在一个用 Guest 认证的问题和一个用 SSO 认证的问题。Guest Embed 的限制清单因为 Guest Embed 不需要你通过 SSO 为每个人创建 Metabase 账号Metabase 无法知道正在观看嵌入内容的人是谁因此也无法为其开放完整的数据访问与全部 Metabase 能力。Guest Embed 无法使用以下能力行级与列级权限数据库路由下钻Drill-through使用情况分析查询构建器AI 对话自定义可视化如果需要这些能力请转向 带 SSO 的 Modular embedding。此外若想在嵌入图表中获得更多交互能力如下钻与自助查询同样建议参考 Modular embedding。进一步阅读嵌入介绍定制 Metabase 的外观Modular embedding 参数详解序列化与实体 ID【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表