如何将您的应用以 iframe 形式集成到 B2CORE

了解如何将第三方 Web 应用以 iframe 形式集成到 B2CORE,包括服务器配置、主题和语言同步,以及通过 postMessage API 进行基于 JWT 的身份验证

B2CORE 支持通过 iframe 将第三方 Web 应用直接嵌入客户 UI。当自定义菜单项配置为 Iframe 行为时,B2CORE 会在界面中加载您的应用,为客户提供无需离开平台的无缝体验。

本指南涵盖两个方面:在 B2CORE Back Office 中配置自定义菜单项,以及准备您的应用以确保其能在 B2CORE iframe 中正常运行。

前提条件

在继续之前,请确保满足以下条件:

第 1 步:配置您的服务器以允许 iframe 嵌入

默认情况下,大多数 Web 服务器和框架会阻止页面被嵌入其他域中的 iframe。要允许 B2CORE 加载您的应用,您必须在服务器上配置相应的 HTTP 响应标头。

您需要设置以下标头中的一个或两个:

Content-Security-Policy

带有 frame-ancestors 指令的 Content-Security-Policy 标头用于控制哪些源可嵌入您的页面。设置此标头以包含您的 B2CORE 实例源:

Content-Security-Policy: frame-ancestors 'self' https://portal.example.com

将 https://portal.example.com 替换为客户所使用的 B2CORE UI 的实际源。如果您的应用需要嵌入多个 B2CORE 实例,可以指定多个以空格分隔的源。

有关更多信息,请参阅 MDN 上的 Content-Security-Policy 文档。

X-Frame-Options

X-Frame-Options 标头是一种可实现类似效果的旧机制。如果您使用它,请将其设置为带有您的 B2CORE 源的 ALLOW-FROM:

X-Frame-Options: ALLOW-FROM https://portal.example.com

并非所有浏览器都支持 X-Frame-Options: ALLOW-FROM 指令。建议将带有 frame-ancestors 指令的 Content-Security-Policy 标头用作主要机制,并仅将 X-Frame-Options 作为对旧版客户端的后备方案。

有关更多信息,请参阅 MDN 上的 X-Frame-Options 文档。

第 2 步:在 B2CORE Back Office 中添加自定义菜单项

要让客户能够访问您的应用,请添加一个具有 iframe 行为的自定义菜单项:

导航至 Promotion > Menu。

点击 General 行中的眼睛图标以查看菜单树。

点击页面右上角的 +Create。

填写必填字段:

  • 在 Name 字段中,输入菜单项的唯一名称。
  • 在 Caption 字段中,输入客户将在菜单中看到的标签。
  • 在 External URL 字段中,指定您的应用 URL。
  • 在 Icon 字段中,指定 SVG 图标的 URL(16x16 px、单色、透明背景)。
  • 在 Custom Behavior 下拉列表中,选择 Iframe。

如有需要,配置可选限制:

  • 若要将可见性限制为特定验证级别,请在 Verification Level Allowance 下拉列表中选择相应级别。
  • 若要将可见性限制为特定客户类型,请在 Client Type Allowance 下拉列表中选择相应类型。

启用 Visible 复选框,使该项目显示在菜单中。

点击 Save 以添加自定义菜单项。

当客户点击此菜单项时,您的应用将在 B2CORE UI 内的 iframe 中加载。

自定义菜单项还提供另外两种行为选项:Same tab(在当前浏览器标签页中打开 URL)和 New tab(在新的浏览器标签页中打开 URL)。iframe 选项是唯一可将您的应用嵌入 B2CORE 界面内的选项。

第 3 步(可选):实现 postMessage 通信协议

如果您的应用需要识别经过身份验证的 B2CORE 用户、匹配 B2CORE UI 主题,或遵循用户选择的语言,您可以实现下述 postMessage 通信协议。此步骤为可选步骤——如果您的应用不需要用户身份验证、主题同步或语言同步,可以跳过此步骤。

消息参考

从您的应用发送至 B2CORE 的消息

消息类型描述载荷
embed-iframe-ready表示 iframe 已加载完毕并准备好接收消息。{ type: "embed-iframe-ready" }
embed-request-jwt-token向 B2CORE 请求 JWT 身份验证令牌。{ type: "embed-request-jwt-token" }

从 B2CORE 发送至您的应用的消息

消息类型描述载荷
embed-theme-change每当 B2CORE UI 主题变更时发送(并会在 embed-iframe-ready 后立即发送一次)。{ type: "embed-theme-change", theme: "dark-theme" | "light-theme" }
embed-language-change每当 B2CORE UI 语言变更时发送(并会在 embed-iframe-ready 后立即发送一次)。{ type: "embed-language-change", lang: "<language-code>" }
embed-jwt-token对令牌请求的成功响应。{ type: "embed-jwt-token", token: "<jwt-string>", expiresAt: "<ISO-8601>" }
embed-jwt-token-error令牌生成失败时的错误响应。{ type: "embed-jwt-token-error", error: "<error-message>" }
embed-logout当 B2CORE 用户退出登录时发送。此前向您的应用签发的任何令牌均不再有效。{ type: "embed-logout" }

lang 字段包含与 B2CORE UI 当前所选语言对应的小写 ISO 639-1 语言代码(例如 en、de、ar)。

通过 embed-jwt-token 签发的 JWT 令牌绑定于签发时已登录的 B2CORE 用户。当该用户退出登录时,B2CORE 会发送 embed-logout,此后不得再使用该令牌。收到此消息后,请丢弃所有缓存令牌、停止计划的刷新任务,并清除用户特定状态。如果之后有其他用户登录,请使用 embed-request-jwt-token 请求新令牌——系统将为新用户签发全新的令牌。

通信流程

您的应用与 B2CORE 之间的消息顺序遵循以下模式:

sequenceDiagram
    participant App as Your App (iframe)
    participant B2CORE as B2CORE (host)

    App->>B2CORE: embed-iframe-ready
    B2CORE-->>App: embed-theme-change (initial theme)
    B2CORE-->>App: embed-language-change (initial language)
    App->>B2CORE: embed-request-jwt-token
    alt success
        B2CORE-->>App: embed-jwt-token
    else failure
        B2CORE-->>App: embed-jwt-token-error
    end
    Note over App,B2CORE: Token nears expiry...
    App->>B2CORE: embed-request-jwt-token
    B2CORE-->>App: embed-jwt-token
    Note over App,B2CORE: User toggles theme...
    B2CORE-->>App: embed-theme-change
    Note over App,B2CORE: User changes language...
    B2CORE-->>App: embed-language-change
    Note over App,B2CORE: User logs out...
    B2CORE-->>App: embed-logout

发送就绪信号。 当您的页面完成加载时,向 B2CORE 发送 embed-iframe-ready 消息。这会告知宿主您的应用已准备好接收数据。

接收当前主题。 B2CORE 会响应包含当前主题(dark-theme 或 light-theme)的 embed-theme-change 消息。将该主题应用于您的 UI。用户切换主题时,您也会收到此消息。

接收当前语言。 B2CORE 还会响应包含 B2CORE UI 当前所选语言代码(例如 en 或 ar)的 embed-language-change 消息。将相应区域设置应用于您的 UI。用户更改语言时,您会再次收到此消息。

请求身份验证令牌。 当您需要识别当前用户时,发送 embed-request-jwt-token。如果令牌生成成功,B2CORE 会响应 embed-jwt-token(包含 JWT 及其过期时间);如果令牌生成失败,则会响应 embed-jwt-token-error。

在令牌过期前刷新令牌。 JWT 的过期时间在 expiresAt 字段中提供(ISO 8601 格式)。在当前令牌过期前请求新令牌,以保持不中断的访问。

处理退出登录。 当 B2CORE 用户退出登录时,B2CORE 会发送 embed-logout。收到后,请丢弃缓存的令牌、取消所有计划的刷新任务,并清除用户特定状态,以免数据泄露给下一位用户。如果之后有其他用户登录,请使用 embed-request-jwt-token 请求新的令牌。

代码示例

您可以在应用中包含以下完整 JavaScript 代码片段:

(function () {
  const B2CORE_ORIGIN = '*'; // Replace with your B2CORE instance origin for production

  let currentToken = null;
  let tokenRefreshTimer = null;

  // --- Send a message to B2CORE ---
  function sendToHost(message) {
    window.parent.postMessage(message, B2CORE_ORIGIN);
  }

  // --- Handle incoming messages from B2CORE ---
  function handleMessage(event) {
    const data = event.data;
    if (!data || !data.type) return;

    switch (data.type) {
      case 'embed-theme-change':
        applyTheme(data.theme);
        break;

      case 'embed-language-change':
        applyLanguage(data.lang);
        break;

      case 'embed-jwt-token':
        handleToken(data.token, data.expiresAt);
        break;

      case 'embed-jwt-token-error':
        console.error('Token error from B2Core:', data.error);
        break;

      case 'embed-logout':
        handleLogout();
        break;
    }
  }

  // --- Apply theme to your UI ---
  function applyTheme(theme) {
    document.documentElement.setAttribute('data-theme', theme);
  }

  // --- Apply language to your UI ---
  function applyLanguage(lang) {
    document.documentElement.setAttribute('lang', lang);
  }

  // --- Handle received JWT token ---
  function handleToken(token, expiresAt) {
    currentToken = token;

    // Schedule a refresh 2 minutes before expiry
    if (tokenRefreshTimer) {
      clearTimeout(tokenRefreshTimer);
    }

    const refreshIn = new Date(expiresAt).getTime() - Date.now() - 2 * 60 * 1000;

    if (refreshIn > 0) {
      tokenRefreshTimer = setTimeout(requestToken, refreshIn);
    } else {
      requestToken();
    }
  }

  // --- Request a JWT token from B2CORE ---
  function requestToken() {
    sendToHost({ type: 'embed-request-jwt-token' });
  }

  // --- Handle B2CORE user logout ---
  function handleLogout() {
    // The token is bound to the user who just logged out — stop using it.
    currentToken = null;

    if (tokenRefreshTimer) {
      clearTimeout(tokenRefreshTimer);
      tokenRefreshTimer = null;
    }

    // Clear any user-specific state in your app here.
  }

  // --- Initialize ---
  window.addEventListener('message', handleMessage);
  sendToHost({ type: 'embed-iframe-ready' });
  requestToken();
})();

在生产环境中,请将 B2CORE_ORIGIN 值替换为您的 B2CORE 实例实际源(例如 'https://portal.example.com')。仅在开发期间可以使用 '*',因为它允许任何源与您的应用通信。

TypeScript 类型定义

如果您的应用使用 TypeScript 构建,可以使用以下类型定义:

type EmbedTheme = 'dark-theme' | 'light-theme';

// Messages: Your App -> B2CORE
interface EmbedIframeReadyMessage {
  readonly type: 'embed-iframe-ready';
}

interface EmbedRequestJwtTokenMessage {
  readonly type: 'embed-request-jwt-token';
}

type EmbedOutboundMessage = EmbedIframeReadyMessage | EmbedRequestJwtTokenMessage;

// Messages: B2CORE -> Your App
interface EmbedThemeChangeMessage {
  readonly type: 'embed-theme-change';
  readonly theme: EmbedTheme;
}

interface EmbedLanguageChangeMessage {
  readonly type: 'embed-language-change';
  readonly lang: string; // ISO 639-1 code, e.g. "en", "de", "ar"
}

interface EmbedJwtTokenMessage {
  readonly type: 'embed-jwt-token';
  readonly token: string;
  readonly expiresAt: string; // ISO 8601
}

interface EmbedJwtTokenErrorMessage {
  readonly type: 'embed-jwt-token-error';
  readonly error: string;
}

interface EmbedLogoutMessage {
  readonly type: 'embed-logout';
}

type EmbedInboundMessage =
  | EmbedThemeChangeMessage
  | EmbedLanguageChangeMessage
  | EmbedJwtTokenMessage
  | EmbedJwtTokenErrorMessage
  | EmbedLogoutMessage;

第 4 步(可选):验证 JWT 令牌

B2CORE 签发的 JWT 令牌可针对 B2CORE API(Admin Panel 后端)公开的 JSON Web Key Set (JWKS) 端点进行验证。这通常是 API/admin 域,而不是面向客户的 UI 域:

https://api.<your-domain>/.well-known/jwks.json

使用此端点获取验证令牌签名所需的公钥。大多数 JWT 库都原生支持基于 JWKS 的验证。

在开发期间进行手动检查时,您可以使用 JWT 解码器工具解码和验证 JWT 令牌。

最后更新于

本页目录