一个 Metabase 之谜
公共链接、公共嵌入和签名嵌入有什么区别?
假设您正在 Metabase 中进行一项有趣的分析,并且需要分享您的工作——首先是为了获得反馈,然后是作为最终产品。
公共链接和嵌入(Public links and embeds)和静态嵌入(static embeds)都是免费的开源方式,可以与没有 Metabase 账户或访问您原始数据权限的人共享 Metabase 项目(如图表和仪表板,但不要局限于此)。
在这些数据共享选项之间进行选择时,您需要考虑:
- 您需要多快共享结果
- 您想添加多少上下文
- 您的数据级别的安全性
你能帮助我们找到隐藏的信息吗?
在本教程中,我们将从 Metabase 的数据分析师的角度探索一系列数据共享用例。我们的工作是调查我们的一位队友留下的一个谜团,他刚要解决 Metabase 最古老的 bug 就失踪了。
我们收到匿名线报,说队友的 git commit 消息中可能隐藏着一条消息,所以我们想分析数据,看看有什么异常或可疑之处。当然,我们也想与我们的社区分享这次调查(毕竟我们是开源的)。
如果您想跳到有趣的部分
仅供内部使用
在公开分享我们正在进行的调查结果之前,我们想获得团队的一些反馈,并确保我们没有泄露任何个人身份信息(PII)。初步分析(图 1)位于我们的内部 Metabase 实例中——此版本将仅与我们的团队共享。

共享 Metabase 仪表板的 URL
创建仪表板的公共链接。
您可以将公共链接添加到实时调查仪表板。我们决定聚合显示 commit 数据,以便更轻松地阅读分析。我们还设置了自定义目标,以便人们可以查看仪表板上显示的每个统计数据的完整 commit 消息。随着我们继续调查,我们可以发布我们的更改,在公共链接上显示最新的分析。
线索 1
在我们的探索性数据分析中,我们查看了 git commit 消息长度的分布。其中一个异常值(消息长度最长)包含以下消息:
update the database sync event publication so that we can actually
track start & END as separate events but part of the same activity.
to do so we add a :tracking-hash to the events when they are published
which is meant to remain consistent throughout the sync, then we
implement our activity tracking code so that we can lookup an existing
activity item and update it based on the custom hash.
我们不确定为什么 END 在这里大写。它可能无关紧要,但我们会继续查找……
下一步:线索 2。
将 Metabase 仪表板添加到网站
接下来,我们想将我们的实时调查仪表板与一个用于评论的网络表单一起显示,以便我们的社区可以去一个地方为调查做出贡献。为此,我们将设置一个新网站,并将我们的仪表板和网络表单作为嵌入式 iframe。
设置网站最简单的方法是使用免费的网站构建器。在这里,我们使用的是Google Sites。如果您不使用 Google Workspace,可以尝试 Squarespace 或 Webflow 等工具。

接下来,我们将回到 Metabase 仪表板的共享选项,并复制公共嵌入下的代码。我们将向 Google 网站添加一个嵌入元素,并将代码片段粘贴在那里。

然后,我们将创建一个公共 Google 表单并将其保存在 Google Drive 中。要将表单添加到我们的 Google 网站,我们可以向下滚动插入菜单(如图 2 所示)并选择表单。
现在,我们有了一个实时调查网站,它显示了我们的 Metabase 仪表板以及一个用于评论的表单。我们的社区将能够:
- 通过 Metabase 仪表板的公共嵌入访问最新的数据和线索。
- 使用嵌入式 Google 表单为搜索做出贡献。
线索 2
既然我们查看了最大异常值,那么查看消息长度最小的 commit 才是有意义的。最短的消息只有三个字符长,并且再次大写。
LAG
下一步:线索 3。
限制对嵌入式 Metabase 仪表板的访问
今天早上,有人用数千个对不存在的查询参数filter=some_spooky_nonsense的请求攻击了我们的 Metabase 公共嵌入。为了保护线索不落入不法分子之手,我们要确保只有经过验证的用户才能访问带有线索的行。
通过将公共嵌入更改为静态嵌入,我们可以添加此额外的安全层。我们希望仪表板的静态嵌入显示:
- 未登录用户无数据。
- 已登录用户 restricted data(除线索外的所有数据)。
- 使用秘密密码登录的用户可获得秘密数据(线索)。
静态嵌入无法与 Google Sites 等网站生成器一起使用,因为我们需要运行自己的 Web 服务器来生成保护我们数据的签名令牌。如果您想继续完成静态嵌入教程的其余部分,您将需要:
- 您自己的 Metabase 实例(及其关联的嵌入密钥)。
- 克隆embedding reference apps 仓库(我们将修改Node 示例)。
- 一份
metabase-mystery数据副本。
设置登录页面
首先,我们需要某种方法来验证尝试访问我们实时调查网站的用户的身份。通常,这通过由身份验证服务(如 Google 登录)支持的登录页面来完成,以便:
- 成功登录后,我们的 Web 服务器会将一个查询参数(如
user=verified)发送到我们 Metabase 仪表板上的过滤器,从而显示线索。 - 登录失败后,Metabase 仪表板过滤器将不会从 Web 服务器接收正确的参数,从而隐藏线索并显示其余数据。
为了演示基于登录的显示和隐藏数据,我们将从login.pug中定义的简单身份验证流程开始(这肯定证明您既真实又无嫌疑)。
form(method="POST" action="/login")
input(type="text" name="username" value="metabot")
input(type="password" name="password" value="unverified")
input(type="hidden" name="redirect" value=redirectUrl)
p Can you be trusted?
button(type="submit" class="primary") Yes
根据用户的登录情况将用户重定向到不同的 URL
为了跟踪用户的登录信息,我们将使用一个名为messageType的变量来修改index.js中的服务器代码。
function checkAuth(req, res, next) {
const messageType = req.session.messageType;
if (messageType) {
return next();
}
req.session.redirectTo = req.path;
return res.redirect("/login");
}
然后,我们将设置一些逻辑来处理不同类型的登录。存储在messageType中的值将用于过滤数据,这些数据将在静态嵌入 URL处显示。
if (username === "metabot" && password === "regularPassword") {
// require a login to view the commit messages
req.session.messageType = "not secret";
res.redirect(req.session.redirectTo);
} else if (username === "metabot" && password === "secretPassword") {
// require a login with the secret password to view the clues
req.session.messageType = "secret";
res.redirect(req.session.redirectTo);
} else {
// allow people without logins to submit comments
res.redirect("/");
}
生成静态嵌入 URL
现在,我们可以更新index.js中的服务器代码,为每个登录用户动态生成静态嵌入的 URL。这些 URL 是安全的,因为它们是用我们的嵌入密钥签名的。服务器还将messageType的值(“secret”或“not secret”)传递给我们 Metabase 仪表板上的过滤器,以隐藏或显示数据中的线索。我们将在下一步中设置此过滤器。
app.get("/signed_dashboard/:id", checkAuth, (req, res) => {
const messageType = req.session.messageType;
const unsignedToken = {
resource: { dashboard: DASHBOARD_ID },
params: { keep_secret: messageType },
exp: Math.round(Date.now() / 1000) + 10 * 60, // 10 minute expiration
};
// sign the JWT token with our secret key
const signedToken = jwt.sign(unsignedToken, MB_EMBEDDING_SECRET_KEY);
// construct the URL of the iframe to be displayed
const iframeUrl = `${MB_SITE_URL}/embed/dashboard/${signedToken}`;
res.render("dashboard", { messageType: req.params.id, iframeUrl: iframeUrl });
});
使用锁定参数限制数据
为了指定应根据用户的登录情况显示的数据行,我们将回到我们的 git commit 数据,并添加一个名为Message Type的自定义列,该列使用case 表达式将带有线索的行设置为“secret”,其余数据设置为“not secret”。

然后,为了确保我们可以限制我们实时调查仪表板上的所有数据,我们将需要为仪表板上的*每个*问题创建一个Message Type列。
数据设置完成后,我们将向实时调查仪表板添加一个过滤器,并将该过滤器链接到我们所有问题中的Message Type列。我们还将“not secret”放在默认值下,默认只显示非线索行。

现在,我们可以启用静态嵌入在我们的仪表板上,并设置一个锁定参数。锁定参数将在登录流程中(取决于使用的密码)从 Web 服务器接收“secret”或“not secret”的messageType值。此锁定参数将在结果显示在静态嵌入 URL之前,将“secret”或“not secret”的值应用于我们*原始*仪表板上的过滤器。

使用不同访问级别的用户查看静态嵌入
一旦我们使用静态嵌入的前端代码更新了layout.pug,我们就可以运行我们的服务器代码来构建一个本地站点,该站点包含指向我们实时调查仪表板的链接以及一个用于评论的嵌入式 Google 表单。

单击链接将提示用户登录以查看数据。迄今为止找到的线索默认隐藏。

要访问带有线索的行,用户必须提供秘密密码。

如果您没有有效的登录凭据,可以通过表单请求访问(或仅仅作为热情的评论者参与此神秘事件)。

线索 3
分布中隐藏的另一个线索——这次是在中位数消息长度处。
fixes mobile password reSET and confirmation #869
开始行动
我们需要更多来自外部数据朋友的帮助。到目前为止,我们已经找到了 END、LAG 和 SET 这几个线索。我们的队友想告诉我们什么?获取数据并进行尝试,看看您是否能解开这个谜团。
点击此处获取提示。
尝试使用 commit 消息长度计算其他摘要统计信息。解决方案并没有通过 Metabase 功能收费(那样会让这个谜团有点太诡异了),但如果您想使用 Metabase 探索数据集,您可以:
- 将 CSV 文件上传到 Google 表格,并将 Metabase 连接到 Google Drive,或
- 将 CSV 直接同步到连接到 Metabase 的数据库或数据仓库。