保护嵌入式 Metabase

如何在不同类型的嵌入中隐藏和保护敏感数据。

使用身份验证和授权保护嵌入

在互联网上保护内容有两种基本方法

  1. 身份验证 关注 某人是谁 (使用诸如 JWTSAML 等标准)。
  2. 授权 关注 某人有权访问什么 (使用诸如 OAuth 2.0 等标准)。

公共嵌入

公共嵌入 不涉及任何身份验证或授权。公共嵌入显示一个公共链接,末尾带有一个唯一的字符串,如下所示

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 授权的静态嵌入

Static embedding with JWT authorization.

此图说明了如何通过签名的 JWT 保护嵌入

  1. 访客到达:您的前端收到显示 Metabase 嵌入 URL 的请求。
  2. 签名请求:您的后端生成带有 签名 JWT 的 Metabase 嵌入 URL。签名的 JWT 应编码您用于过滤数据的任何查询 参数
  3. 响应:您的 Metabase 后端根据签名 JWT 中编码的查询参数返回数据。
  4. 成功:您的前端显示带有正确数据的嵌入式 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 登录名,我们将需要

  • 具有“帐户”数据的 可嵌入的仪表板
  • “帐户 ID”过滤器的 锁定参数
  • 我们的嵌入应用程序(我们想要嵌入 Metabase 的 Web 应用程序)中的登录流程。

流程可能如下所示

  1. 客户登录到我们的 Web 应用程序。
  2. 我们的应用程序后端根据登录期间使用的帐户电子邮件查找客户的 account_id
  3. 我们的应用程序后端使用 Metabase 的 密钥生成带有签名 JWT 的嵌入 URL。签名的 JWT 对查询参数进行编码,以在 Account ID = account_id 上过滤“帐户”仪表板。
  4. Metabase 在静态嵌入 URL 返回已过滤的仪表板。
  5. 我们的应用程序前端在 iframe 中显示已过滤的仪表板。

有关代码示例,请参阅 静态嵌入参考应用程序

交互式嵌入在单流程中进行身份验证和授权

交互式嵌入与 SSO (JWTSAML) 集成,以在单流程中进行身份验证和授权。身份验证集成可以轻松地将用户属性(例如,人员的角色或部门)映射到精细的数据访问级别,包括

具有 SSO 的交互式嵌入

Interactive embedding with SSO.

此图显示了如何使用 SSO 保护交互式嵌入

  1. 访客到达:您的前端收到显示所有内容的请求,包括 Metabase 组件(例如,React 组件)。
  2. 加载嵌入:您的前端组件使用您的 嵌入 URL 加载 Metabase 前端。
  3. 检查会话:为了在嵌入 URL 上显示数据,您的 Metabase 后端检查是否有有效的会话(已登录的访客)。
  4. 如果没有有效的会话:
    • 重定向到 SSO:您的 Metabase 前端将访客重定向到您的 SSO 登录页面。
    • SSO 身份验证:您的 SSO 流程验证访客身份,并根据其身份生成会话。会话信息应编码用户属性,例如组成员身份和 数据沙盒 权限。
    • 重定向到 Metabase:您的 SSO 流程使用会话信息将访客重定向到您的 Metabase 前端。
  5. 请求:您的 Metabase 前端将数据请求连同会话信息一起发送到 Metabase 后端。
  6. 响应:您的 Metabase 后端根据会话信息中编码的用户属性返回数据。
  7. 成功:您的前端组件显示嵌入式 Metabase 页面,其中包含已登录访客的正确数据。

步骤 4 的机制会因您是使用 JWT 还是 SAML 进行 SSO 而略有不同。

示例:使用 SSO 和数据沙盒保护数据

在我们的静态嵌入示例中,我们使用 锁定参数 来显示“帐户”表的安全过滤视图。

交互式嵌入和SSO集成的优点在于,我们不必为每个嵌入手动管理锁定的参数。相反,我们可以将用户属性从我们的身份提供商 (IdP) 映射到 Metabase 中的权限数据沙箱。人们可以从首次登录开始就获得身份验证和授权,从而自助服务于特定的数据子集。

让我们扩展我们的“账户”示例,以包含“租户 ID”。租户 ID 代表一组客户的父组织。

租户 ID 帐户 ID 计划 状态
999 1 基本 活动
999 2 基本 活动
999 3 基本 非活动
777 4 高级 非活动
777 5 高级 活动

我们仍然希望向客户公开“账户”表,但有一些额外的要求:

  • 单个客户只能查看其自身账户 ID 的数据。
  • 租户可以查看其所有子账户(但不能查看其他租户的数据)。

要设置这些多租户权限,我们需要:

  1. 在我们的 IdP 中创建一个 primary_id 属性,以唯一标识所有租户和客户。
  2. 在我们的 IdP 中创建一个名为 role 的用户属性,并为每个将使用 Metabase 的人将其设置为 tenantcustomer
  3. 在 Metabase 中创建两个组:租户和客户。
  4. 在 Metabase 和我们的 IdP 之间同步组成员关系,以便:
    • 具有 role=tenant 的人员被分配到“租户”组。
    • 具有 role=customer 的人员被分配到“客户”组。
  5. 为每个组设置“账户”表的沙盒视图:
    • 对于“客户”组,“账户”表将被沙盒化(过滤)为 Account ID = primary_id
    • 对于“租户”组,“账户”表将被沙盒化为 Tenant ID = primary_id

当租户 A 首次使用 SSO 登录时:

  • Metabase 将为其创建一个账户。
  • 我们的 IdP 将把 role=tenantprimary_id=999 属性发送到 Metabase。
  • Metabase 将自动将租户 A 分配到“租户”组。
  • 租户 A 将获得“租户”组的权限(包括数据沙箱)。
  • 租户 A 将在 Metabase 中的任何地方看到“账户”表的沙盒视图。
租户 ID 帐户 ID 计划 状态
999 1 基本 活动
999 2 基本 活动
999 3 基本 非活动

当客户 1 登录时,他们将根据其 roleprimary_id 属性看到“账户”表的另一个过滤版本。

租户 ID 帐户 ID 计划 状态
A 1 基本 活动

示例应用

延伸阅读