保护嵌入式 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 编码查询参数,以在“账户”仪表板上按 账户 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. 为每个组设置“账户”表的沙盒视图
    • 对于“客户”组,“账户”表将被沙盒化(筛选)为 账户 ID = primary_id
    • 对于“租户”组,“账户”表将被沙盒化为 租户 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 基本 活跃

示例应用

延伸阅读

© . All rights reserved.