Metabase 谜题
公共链接、公共嵌入和签名嵌入之间有什么区别?
假设您正在 Metabase 中进行有趣的分析,并且您需要分享您的工作——首先是为了获得反馈,然后作为最终产品。
公共链接和嵌入,以及 静态嵌入 都是免费的开源方式,供您与没有 Metabase 帐户或访问原始数据权限的人员共享 Metabase 项目(如图表和仪表盘,但 不要限制自己)。
在选择这些数据共享选项时,您需要考虑
- 您需要多快分享结果
- 您想要添加多少上下文
- 围绕数据的安全级别
您能帮助我们找到隐藏的信息吗?
在本教程中,我们将从 Metabase 数据分析师的角度探讨一系列数据共享用例。我们的工作是调查我们一位队友留下的谜题,这位队友在即将解决 Metabase 最古老的错误时消失了。
我们收到匿名提示,称我们队友的 git 提交消息中可能隐藏着一条信息,因此我们想分析数据,找出任何显得奇怪或可疑的东西。当然,我们也想与我们的社区分享调查结果(毕竟我们是开源的)。
如果您想跳到有趣的部分
仅供内部使用
在我们公开分享正在进行的调查结果之前,我们想获得团队的一些反馈,并确保我们没有泄露任何个人身份信息 (PII)。初始分析(图 1)位于我们的内部 Metabase 实例中——此版本将仅与我们的团队共享。
共享 Metabase 仪表盘的 URL
为我们的仪表盘创建公共链接。
您可以将指向 实时调查仪表盘的公共链接添加到书签。我们决定以聚合方式显示提交数据,以便更轻松地阅读分析结果。我们还设置了自定义目标,以便人们可以查看与仪表盘上显示的每个统计数据关联的完整提交消息。当我们继续调查时,我们可以发布我们的更改,以在公共链接处显示最新的分析结果。
线索 1
在我们的探索性数据分析期间,我们查看了 git 提交消息长度的分布。其中一个异常值(长度最长的消息)包含以下消息
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 仪表盘添加到网站
接下来,我们想将我们的实时调查仪表盘与评论 Web 表单一起显示,以便我们的社区可以转到一个地方来为调查做出贡献。为此,我们将设置一个新的网站,并将我们的仪表盘和 Web 表单添加为嵌入式 iframe。
设置网站的最简单方法是使用免费的站点构建器。在这里,我们使用 Google Sites。如果您不使用 Google Workspace,您可以尝试像 Squarespace 或 Webflow 这样的工具。
接下来,我们将返回到我们的 Metabase 仪表盘上的共享选项,并复制 公共嵌入 下的代码。我们将嵌入元素添加到 Google 站点,并将代码片段粘贴到那里
然后,我们将创建一个公共 Google 表单并将其保存在 Google 云端硬盘中。要将表单添加到我们的 Google 站点,我们可以向下滚动 插入 菜单(如图 2 所示),然后选择 表单。
现在,我们有了一个实时调查网站,其中显示了我们的 Metabase 仪表盘以及评论表单。我们的社区将能够
- 从我们的 Metabase 仪表盘的公共嵌入访问最新的数据和线索。
- 使用嵌入式 Google 表单为搜索做出贡献。
线索 2
既然我们查看了最大异常值,那么只查看消息长度最小的提交也很有意义。最短的消息只有三个字符长,并且再次大写
LAG
下一步:线索 3。
限制对嵌入式 Metabase 仪表盘的访问
今天早上,有人使用数千个针对不存在的查询参数 filter=some_spooky_nonsense
的请求攻击了我们的 Metabase 公共嵌入。为了保护线索不落入坏人之手,我们想确保只有经过验证的用户才能访问包含线索的行。
我们可以通过将公共嵌入更改为静态嵌入来添加此额外的安全层。我们希望仪表盘的静态嵌入显示
- 未登录用户无数据。
- 已登录用户受限数据(线索之外的所有内容)。
- 使用密码登录的用户的秘密数据(线索)。
静态嵌入不适用于像 Google Sites 这样的站点生成器,因为我们需要运行自己的 Web 服务器才能生成签名令牌来保护我们的数据。如果您想继续学习其余的静态嵌入教程,您将需要
- 您自己的 Metabase 实例(以及关联的嵌入密钥)。
- 嵌入参考应用程序存储库的克隆(我们将修改 Node 示例)。
metabase-mystery
数据的副本。
设置登录页面
首先,我们需要某种方法来验证尝试访问我们实时调查网站的人的身份。通常,这是通过由身份验证服务(如 Google 登录)支持的登录页面完成的,以便
- 登录成功后,我们的 Web 服务器将向我们 Metabase 仪表盘上的过滤器发送像
user=verified
这样的查询参数,从而显示线索。 - 登录失败后,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 提交数据,并添加一个名为 消息类型 的自定义列,该列使用 case 表达式 将包含线索的行设置为“secret”,其余数据设置为“not secret”。
然后,为了确保我们可以限制我们的实时调查仪表盘上的所有数据,我们需要为仪表盘上的每个问题创建一个 消息类型 列。
设置数据后,我们将向我们的实时调查仪表盘添加一个过滤器,并将该过滤器链接到我们每个问题中的所有 消息类型 列。我们还将在 默认值 下放置“not secret”,以便默认情况下仅显示非线索行。
现在,我们可以在我们的仪表盘上启用静态嵌入,并设置一个锁定参数。锁定参数将在登录流程期间从 Web 服务器接收 messageType
值“secret”或“not secret”(具体取决于使用的密码)。此锁定参数将在结果显示在 静态嵌入 URL 之前,将值“secret”或“not secret”应用于我们原始仪表盘上的过滤器。
查看具有不同访问级别的静态嵌入
在我们使用 静态嵌入的前端代码 更新 layout.pug
后,我们可以运行我们的服务器代码来构建一个本地站点,其中包含指向我们的实时调查仪表盘和嵌入式 Google 评论表单的链接
单击该链接将提示人们登录以查看数据。到目前为止,我们发现的线索默认情况下是隐藏的
要访问包含线索的行,人们必须提供密码
如果您没有有效的登录名,您可以通过表单请求访问(或者只是作为热心的评论者参与谜题)
线索 3
隐藏在分布中的另一个线索——这次是在消息长度的中位数
fixes mobile password reSET and confirmation #869
游戏开始了
我们需要来自数据朋友的更多帮助。到目前为止,我们已经找到了线索 END、LAG 和 SET。我们的队友想告诉我们什么?获取数据并尝试一下,看看您是否可以解开谜题。
单击此处获取提示。
尝试使用提交消息长度计算其他摘要统计信息。解决方案不会因 Metabase 功能而受到付费限制(这会使这个谜题有点太可怕),但如果您想使用 Metabase 探索数据集,您可以
- 将 CSV 文件上传到 Google 表格,然后将 Metabase 连接到 Google 云端硬盘,或者
- 将 CSV 直接同步到连接到 Metabase 的数据库或数据仓库。
延伸阅读
下一步:多租户自助分析
嵌入整个 Metabase 应用程序(包括查询构建器),以便人们安全地个性化访问数据。