保护嵌入式 Metabase
如何在不同类型的嵌入中隐藏和保护敏感数据。
使用身份验证和授权保护嵌入
在互联网上保护内容有两种基本方法
公共嵌入
公共嵌入 不涉及任何身份验证或授权。公共嵌入显示一个公共链接,末尾带有一个唯一的字符串,如下所示
http://my-metabase.com/public/dashboard/184f819c-2c80-4b2d-80f8-26bffaae5d8b
该字符串(在本例中为:184f819c-2c80-4b2d-80f8-26bffaae5d8b
)唯一标识您的 Metabase 问题或仪表板。由于公共嵌入不进行任何身份验证或授权,因此任何拥有 URL 的人都可以查看数据。
示例:公共链接中的过滤器无法保护数据
那么,有人如何利用公共嵌入?假设我们有一个显示“帐户”数据的仪表板
帐户 ID | 计划 | 状态 |
---|---|---|
1 | 基本 | 活动 |
2 | 基本 | 活动 |
3 | 基本 | 非活动 |
4 | 高级 | 非活动 |
5 | 高级 | 活动 |
我们想要添加一个“状态 = 活动”过滤器,并在嵌入中显示仪表板的公共链接
帐户 ID | 计划 | 状态 |
---|---|---|
1 | 基本 | 活动 |
2 | 基本 | 活动 |
5 | 高级 | 活动 |
为了应用和隐藏“状态 = 活动”过滤器,我们将在嵌入中公共链接的末尾添加 查询参数
http://my-metabase.com/public/dashboard/184f819c-2c80-4b2d-80f8-26bffaae5d8b?status=active#hide_parameters=status
即使我们已从嵌入中隐藏了过滤器,但有人可以获取嵌入中使用的公共链接,并删除查询参数 ?status=active
http://my-metabase.com/public/dashboard/184f819c-2c80-4b2d-80f8-26bffaae5d8b
加载不带查询参数的公共链接将从数据中删除“状态 = 活动”过滤器。该人将获得对原始“帐户”数据的访问权限,包括具有非活动帐户的行。
静态嵌入通过 JWT 授权
静态嵌入使用 JWT 授权流程 来执行两件事
- 签署资源(例如,图表或仪表板的 URL),以确保只有您的嵌入应用程序可以从您的 Metabase 请求数据。
- 签署参数(例如,仪表板过滤器),以防止人们 更改过滤器 并获得对其他数据的访问权限。
静态嵌入没有用户会话
静态嵌入不会在 Metabase 端验证人员的身份,因此人们无需创建 Metabase 帐户即可查看静态嵌入。但是,如果没有 Metabase 帐户,Metabase 将无法记住用户或其会话,这意味着
- Metabase 权限 和 数据沙盒 将不起作用 — 如果您需要锁定敏感数据,则必须为 每个 静态嵌入设置 锁定参数。
- 静态嵌入中的任何过滤器选择将在签名的 JWT 过期后重置。
- 所有静态嵌入使用情况都将显示在 使用情况分析 中的“外部用户”下。
静态嵌入安全性 vs. 交互式嵌入安全性
静态嵌入仅保证对您的 Metabase 数据的授权访问(您决定 什么 是可访问的)。
如果您想根据某人的身份来保护您的静态嵌入(您决定 谁 可以访问 什么 ),则需要设置自己的身份验证流程,并手动将其连接到每个静态嵌入上的 锁定参数。请注意,锁定参数本质上是过滤器,因此您只能在静态嵌入中设置 行级 限制。
如果您想要一种更简单的方法来为不同的客户嵌入不同的数据视图(而不允许客户看到彼此的数据),请了解 交互式嵌入如何在单流程中进行身份验证和授权。
使用 JWT 授权的静态嵌入
此图说明了如何通过签名的 JWT 保护嵌入
- 访客到达:您的前端收到显示 Metabase 嵌入 URL 的请求。
- 签名请求:您的后端生成带有 签名 JWT 的 Metabase 嵌入 URL。签名的 JWT 应编码您用于过滤数据的任何查询 参数。
- 响应:您的 Metabase 后端根据签名 JWT 中编码的查询参数返回数据。
- 成功:您的前端显示带有正确数据的嵌入式 Metabase 页面。
示例:通过静态嵌入上的锁定参数保护数据
在 公共嵌入示例 中,我们(可能不明智地)向您展示了有人如何通过编辑其查询参数来利用唯一的公共链接。
让我们回到我们的“帐户”示例
帐户 ID | 计划 | 状态 |
---|---|---|
1 | 基本 | 活动 |
2 | 基本 | 活动 |
3 | 基本 | 非活动 |
4 | 高级 | 非活动 |
5 | 高级 | 活动 |
请记住,我们可以通过在嵌入 URL 的末尾包含查询参数来过滤公共嵌入中的数据
http://my-metabase.com/public/dashboard/184f819c-2c80-4b2d-80f8-26bffaae5d8b?status=active
帐户 ID | 计划 | 状态 |
---|---|---|
1 | 基本 | 活动 |
2 | 基本 | 活动 |
5 | 高级 | 活动 |
使用静态嵌入,我们可以通过在签名的 JWT 中编码查询参数来“锁定”过滤器。例如,假设我们将“状态 = 活动”过滤器设置为 锁定参数。?status=active
查询参数将编码在签名的 JWT 中,因此它在静态嵌入 URL 中将不可见或不可编辑
http://my-metabase.com/dashboard/your_signed_jwt
如果有人尝试在静态嵌入 URL 的末尾添加(未签名的)查询参数,例如这样
http://my-metabase.com/dashboard/your_signed_jwt?status=inactive
Metabase 将拒绝此未经授权的数据请求,因此非活动帐户行将保持在嵌入中隐藏。
示例:将用户属性发送到锁定参数
假设我们想要向我们的客户公开“帐户”表,以便客户可以根据“帐户 ID”查找行。
帐户 ID | 计划 | 状态 |
---|---|---|
1 | 基本 | 活动 |
2 | 基本 | 活动 |
3 | 基本 | 非活动 |
4 | 高级 | 非活动 |
5 | 高级 | 活动 |
如果我们想避免为每个客户创建 Metabase 登录名,我们将需要
流程可能如下所示
- 客户登录到我们的 Web 应用程序。
- 我们的应用程序后端根据登录期间使用的帐户电子邮件查找客户的
account_id
。 - 我们的应用程序后端使用 Metabase 的 密钥 来 生成带有签名 JWT 的嵌入 URL。签名的 JWT 对查询参数进行编码,以在
Account ID = account_id
上过滤“帐户”仪表板。 - Metabase 在静态嵌入 URL 返回已过滤的仪表板。
- 我们的应用程序前端在 iframe 中显示已过滤的仪表板。
有关代码示例,请参阅 静态嵌入参考应用程序。
交互式嵌入在单流程中进行身份验证和授权
交互式嵌入与 SSO (JWT 或 SAML) 集成,以在单流程中进行身份验证和授权。身份验证集成可以轻松地将用户属性(例如,人员的角色或部门)映射到精细的数据访问级别,包括
具有 SSO 的交互式嵌入
此图显示了如何使用 SSO 保护交互式嵌入
- 访客到达:您的前端收到显示所有内容的请求,包括 Metabase 组件(例如,React 组件)。
- 加载嵌入:您的前端组件使用您的 嵌入 URL 加载 Metabase 前端。
- 检查会话:为了在嵌入 URL 上显示数据,您的 Metabase 后端检查是否有有效的会话(已登录的访客)。
- 如果没有有效的会话:
- 重定向到 SSO:您的 Metabase 前端将访客重定向到您的 SSO 登录页面。
- SSO 身份验证:您的 SSO 流程验证访客身份,并根据其身份生成会话。会话信息应编码用户属性,例如组成员身份和 数据沙盒 权限。
- 重定向到 Metabase:您的 SSO 流程使用会话信息将访客重定向到您的 Metabase 前端。
- 请求:您的 Metabase 前端将数据请求连同会话信息一起发送到 Metabase 后端。
- 响应:您的 Metabase 后端根据会话信息中编码的用户属性返回数据。
- 成功:您的前端组件显示嵌入式 Metabase 页面,其中包含已登录访客的正确数据。
步骤 4 的机制会因您是使用 JWT 还是 SAML 进行 SSO 而略有不同。
示例:使用 SSO 和数据沙盒保护数据
在我们的静态嵌入示例中,我们使用 锁定参数 来显示“帐户”表的安全过滤视图。
交互式嵌入和SSO集成的优点在于,我们不必为每个嵌入手动管理锁定的参数。相反,我们可以将用户属性从我们的身份提供商 (IdP) 映射到 Metabase 中的权限和数据沙箱。人们可以从首次登录开始就获得身份验证和授权,从而自助服务于特定的数据子集。
让我们扩展我们的“账户”示例,以包含“租户 ID”。租户 ID 代表一组客户的父组织。
租户 ID | 帐户 ID | 计划 | 状态 |
---|---|---|---|
999 | 1 | 基本 | 活动 |
999 | 2 | 基本 | 活动 |
999 | 3 | 基本 | 非活动 |
777 | 4 | 高级 | 非活动 |
777 | 5 | 高级 | 活动 |
我们仍然希望向客户公开“账户”表,但有一些额外的要求:
- 单个客户只能查看其自身账户 ID 的数据。
- 租户可以查看其所有子账户(但不能查看其他租户的数据)。
要设置这些多租户权限,我们需要:
- 在我们的 IdP 中创建一个
primary_id
属性,以唯一标识所有租户和客户。 - 在我们的 IdP 中创建一个名为
role
的用户属性,并为每个将使用 Metabase 的人将其设置为tenant
或customer
。 - 在 Metabase 中创建两个组:租户和客户。
- 在 Metabase 和我们的 IdP 之间同步组成员关系,以便:
- 具有
role=tenant
的人员被分配到“租户”组。 - 具有
role=customer
的人员被分配到“客户”组。
- 具有
- 为每个组设置“账户”表的沙盒视图:
- 对于“客户”组,“账户”表将被沙盒化(过滤)为
Account ID = primary_id
。 - 对于“租户”组,“账户”表将被沙盒化为
Tenant ID = primary_id
。
- 对于“客户”组,“账户”表将被沙盒化(过滤)为
当租户 A 首次使用 SSO 登录时:
- Metabase 将为其创建一个账户。
- 我们的 IdP 将把
role=tenant
和primary_id=999
属性发送到 Metabase。 - Metabase 将自动将租户 A 分配到“租户”组。
- 租户 A 将获得“租户”组的权限(包括数据沙箱)。
- 租户 A 将在 Metabase 中的任何地方看到“账户”表的沙盒视图。
租户 ID | 帐户 ID | 计划 | 状态 |
---|---|---|---|
999 | 1 | 基本 | 活动 |
999 | 2 | 基本 | 活动 |
999 | 3 | 基本 | 非活动 |
当客户 1 登录时,他们将根据其 role
和 primary_id
属性看到“账户”表的另一个过滤版本。
租户 ID | 帐户 ID | 计划 | 状态 |
---|---|---|---|
A | 1 | 基本 | 活动 |