---
title: Web App 集成
description: 如何在客户端集成 Web & SDK 合约——重定向流与 iFrame SDK 配置。
canonical: https://developer.unico.io/zh-CN/dual-api/developers/sdks-and-tools/web/web-integration/
locale: zh-CN
generated_by: markdown-export
---

本页介绍 Unico 旅程的工作方式，以及可用于将其集成到应用程序中的集成模型。

**旅程**是用户为完成身份验证而经历的一系列步骤。例如：拍摄证件照片和进行人脸采集（活体检测）。

Unico 负责管理整个体验。集成所需的工作量极小：旅程通过 **CreateProcess** 创建，用户被引导至该旅程，并在最后接收结果。中间发生的一切（界面、提示、校验）都已构建完成并由 Unico 维护。

:::tip[选择你的集成方式]

- **Web SDK**（`unico-webframe` 包）：当你的后端已经控制身份验证流程，且只需要客户端的采集组件时使用。它将 `base64` + 加密的 JWT 直接返回到你的回调中；由你管理 API 调用。
- **Web App Integration**（`idpay-b2b-sdk` 包）：当你希望由 Unico 编排整个旅程（多步骤流程、证件采集 + 活体检测）时使用。`idpay-b2b-sdk` 包为嵌入式 **Journeys SDK**（iFrame）模型提供支持；**直接访问**（重定向）模型则无需任何库。
  :::

## 两种集成模型

每个客户的需求各不相同。Unico 提供**两种模型**来引导用户进入旅程。

| 模型             | 适用于                                                       |
| ---------------- | ------------------------------------------------------------ |
| **直接访问**     | 已使用 WebView 的移动应用，或旅程可以在主页面之外进行的 Web 流程 |
| **Journeys SDK** | 需要集成、无缝体验，并希望让用户保持在同一环境中的 Web 应用   |

### 直接访问

用户被**重定向到由 Unico 托管的链接**，旅程在该处进行。完成后，用户会返回到创建流程时定义的 URL（`callbackUri` 参数）。

这是最易于采用的方式：无需安装任何库，并且在旅程不需要发生在应用程序自身页面内时效果良好。另一方面，将用户带离客户的环境往往会带来更多摩擦，从而导致更高的流失率。

创建流程后，API 响应中会包含由 Unico 托管的旅程 URL。有两种常见的方式可将用户引导至该 URL：

- **标准重定向。** 用户被直接重定向到旅程 URL。完成后，Unico 会将其重定向回创建流程时定义的 `callbackUri`。
- **使用 `window.open()` 打开新标签页。** 旅程在新的浏览器标签页中打开，使用户保持在独立的上下文中。在这种情况下，建议监听 URL 变化为 `callbackUri`，并在流程完成后关闭标签页。有关该 API 的详细信息，请参阅 [MDN 文档](https://developer.mozilla.org/en-US/docs/Web/API/Window/open)。

```mermaid
sequenceDiagram
    participant Unico as Unico backend service
    participant Backend as Customer backend server
    participant Frontend as Customer frontend application
    participant Hosted as Unico hosted frontend application

    Frontend->>Backend: start kyc flow
    Backend->>Unico: call createProcess
    Unico->>Backend: return Unico process info
    Backend->>Frontend: return Unico process info
    Frontend->>Hosted: redirect user to process url
    Note over Hosted: User journey
    Hosted->>Frontend: redirect user to callback url

    critical Get process result
        Frontend->>Backend: signals that journey was finished
        Backend->>Unico: call getProcess
        opt Webhook
            Note over Backend: In addition to getProcess, you can use the Webhook implementation to ensure a fallback in obtaining the process result.
        end
    end
```

在移动应用中，通常使用 **WebView** 直接打开旅程，无需额外的重定向。在这种情况下，`callbackUri` 还接受 **deeplink**，从而允许旅程完成后触发打开原生应用中的特定界面。只需将 deeplink 配置为返回目标，操作系统就会负责将用户路由到正确的位置。

```mermaid
sequenceDiagram
    participant Unico as Unico backend service
    participant Backend as Customer backend server
    participant App as Customer mobile application
    participant Hosted as Unico hosted frontend application

    App->>Backend: start kyc flow
    Backend->>Unico: call createProcess
    Unico->>Backend: return Unico process info
    Backend->>App: return Unico process info
    App->>Hosted: open the process url in a webview
    Note over Hosted: User journey
    Hosted->>App: redirect user to the deeplink (callback url)

    critical Get process result
        App->>Backend: signals that journey was finished
        Backend->>Unico: call getProcess
        opt Webhook
            Note over Backend: In addition to getProcess, you can use the Webhook implementation to ensure a fallback in obtaining the process result.
        end
    end
```

### Journeys SDK

旅程在**应用程序自身内部**进行，不会让用户离开其上下文。**Journeys SDK** 安装在应用程序中，用于在需要时打开旅程。

这是实现更加集成、无缝体验的推荐路径，让用户始终保持在同一环境中，从而往往能减少整个流程中的摩擦和流失。

Unico 提供了一个与现代浏览器兼容的 JavaScript 库，只需几行代码即可将旅程集成到几乎任何应用程序中。

#### 兼容性

该库的设计目标是无摩擦地融入任何项目，无论使用何种技术栈：

- **任何 Web 应用。** 以 UMD 格式分发，可在通过现代打包工具（如 webpack 或 Vite）导入时工作。与任何框架（React、Angular、Vue）或纯 JavaScript 兼容。
- **现代浏览器。** 该库已包含 Promises 和 `async/await` 等特性所需的 polyfill，从而将兼容性扩展到较旧版本的浏览器。
- **标准 Web API。** 旅程基于浏览器的原生能力运行，不依赖项目中的插件或外部库。

#### SDK 的内部工作原理

打开旅程时，SDK 会将一个 iFrame 插入页面，并从那一刻起接管整个视觉体验。每个步骤的界面、脚本和资源都在该 iFrame 内运行，从用户开始的那一刻直到流程完成。

这一架构决策是有意为之的：iFrame 隔离确保 Unico 旅程不会干扰应用程序的样式或行为。没有任何脚本会泄漏到外部上下文，也没有任何 CSS 规则会与应用程序自身的样式冲突。其结果是为最终用户带来一致的体验，并将对客户产品的影响降到最低。

由于 Unico 负责创建和管理 iFrame，旅程的改进（无论是性能、体验还是校验方面）都会自动交付给所有用户，而无需对已集成的应用程序进行任何更改。集成将始终以可用的最佳优化运行，无需跟踪或响应平台的每次演进。

#### 开始使用

****步骤 1**：安装**

`idpay-b2b-sdk` 包在 IDPay 支付旅程和身份验证旅程之间共享。对于身份验证用例，请按照下面步骤所示导入 `ByUnicoSDK` 类。

```bash
  npm install idpay-b2b-sdk
```

安装 Journeys SDK 的推荐方式是通过 **npm** 或 **yarn** 等依赖管理器，从 **npm registry** 上提供的包进行安装。这种方式不仅简化了安装和依赖管理，还能清晰地控制所使用的版本，并便于在每次发布新版本时进行更新。

SDK 遵循**语义化版本控制（SemVer）**，这意味着 patch 和 minor 更新不会引入破坏性变更。可以安全地将项目配置为自动接收这些更新。可能需要调整集成的变更会保留给 major 版本，并始终附带迁移指南。

:::tip[保持 SDK 为最新版本]
保持最新版本之所以特别重要，有两个原因。第一是**安全性**：每当发现漏洞或出现加强通信协议的机会时，都会发布安全补丁。运行过时的版本意味着放弃这些修复，并使流程暴露于不必要的风险之中。第二是**稳定性**：错误修复也以相同方式分发，旧版本可能存在在较新版本中已解决的行为。
:::

开始之前，请向 Unico 支持团队注册你的域名。所有域名都必须使用 HTTPS。

****步骤 2**：调用 `init(options)`**

初始化 SDK 并预加载旅程正确运行所需的脚本，为最终用户带来更流畅的体验。请在流程中尽早调用它。

| 参数    | 必填 | 说明                              |
| ------- | ---- | --------------------------------- |
| `token` | 是   | Create Process API 返回的流程令牌 |
| `env`   | 否   | 仅在测试环境中设置为 `'uat'`      |

```javascript
import { ByUnicoSDK } from 'idpay-b2b-sdk';

ByUnicoSDK.init({
  token,
  // env: 'uat' // 仅用于测试环境
});
```

****步骤 3**：调用 `open(options)`**

显示 iFrame 并为用户启动旅程。从此刻起，一切都在 iFrame 内部自动进行，无需管理任何中间步骤。

| 参数                       | 必填 | 说明                              |
| -------------------------- | ---- | --------------------------------- |
| `transactionId`            | 是   | Create Process API 返回的流程 ID  |
| `token`                    | 是   | Create Process API 返回的流程令牌 |
| `onFinish`                 | 是   | 旅程结束或被关闭时执行的回调      |
| `onWidgetVisibilityChange` | 否   | 小组件可见状态变化时执行的回调    |

与应用程序的下一次交互发生在旅程结束时，无论用户是完成了它还是关闭了它。届时，SDK 会调用作为参数传入 `open` 的 **`onFinish`** 回调。此后，应用程序可以调用 **`getProcess`** API 来检查结果，或者在更倾向于异步方式时等待 **Webhook** 通知。

除了查询结果之外，建议使用 `onFinish` 来处理应用程序的前端状态：

- **避免循环。** 防止在旅程结束后用户立即再次触发流程时，进程被立即且不必要地重新创建。
- **流程管理。** 确保用户被引导至应用程序的下一步，避免在旅程关闭后停留在无法退出的界面上。

:::warning
`onFinish` 回调表示用户已完成旅程，但并不保证审批通过。流程可能因 Unico 某条校验规则未通过而结束。通过 `getProcess` 查询或接收 Webhook 通知并非可选项：它们是实际结果的唯一来源，应用程序的行为必须以此为依据。不得单独使用 `onFinish` 来判断用户是否获得批准。
:::

`onFinish` 回调会接收一个描述旅程如何结束的对象：

| 字段                      | 类型                | 说明                                                                  |
| ------------------------- | ------------------- | --------------------------------------------------------------------- |
| `type`                    | string              | 旅程结束的方式：`'FINISH'`（已完成）或 `'CLOSE'`（用户在完成前关闭）   |
| `transaction`             | object \| undefined | 当 `type` 为 `'FINISH'` 时存在；当 `type` 为 `'CLOSE'` 时为 `undefined` |
| `transaction.id`          | string              | 流程标识符（与传入的 `transactionId` 相同）                           |
| `transaction.redirectUrl` | string              | 旅程结束后重定向用户的 URL                                            |

处理 **`onWidgetVisibilityChange`** 回调是可选的，对你的用例可能并不相关。每当小组件的可见状态发生变化时都会调用它，且仅在一种特定场景下有用：某些旅程会显示透明背景，使应用程序页面在体验后面保持可见。在验证流程中显示自有模态框的应用程序（例如，作为多个 KYC 提供商之间编排的一部分）可能最终会将该模态框显示在 Unico 小组件后面，从而降低视觉体验。在这种情况下，该回调允许应用程序在 Unico 旅程处于活动状态时隐藏任何额外的视觉元素，并在结束后恢复它们。如果你的应用程序没有任何可能与小组件重叠的 UI，则可以放心地省略它。

```javascript
ByUnicoSDK.open({
  transactionId: '9bc22bac-1e64-49a5-94d6-9e4f8ec9a1bf',
  token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
  onFinish: ({ transaction, type }) => {
    if (type === 'FINISH') {
      // 旅程已完成（transaction = { id, redirectUrl }）：在此继续你的流程。
    }
    // type === 'CLOSE' → 用户在完成前关闭；
  },
  // 可选：仅当你的应用显示可能与小组件重叠的 UI 时才需要。
  onWidgetVisibilityChange: (visible) => {
    // 根据小组件可见性隐藏或恢复你的模态框
  },
});

// 如需随时显式关闭 SDK：
ByUnicoSDK.close();
```

下面的时序图展示了如何使用 SDK 和 API 结果来配置 iFrame：

```mermaid
sequenceDiagram
    participant Unico as Unico backend service
    participant Backend as Customer backend server
    participant Frontend as Customer frontend application
    participant SDK as ByUnicoSDK

    Frontend->>Backend: start kyc flow
    Backend->>Unico: call createProcess
    Unico->>Backend: return Unico process info
    Backend->>Frontend: return Unico process info
    Note over Frontend: Initialize the Unico journey as soon as it is determined that the KYC flow is required

    critical Unico journey initialization
        Frontend->>SDK: byUnicoSDK.init
        SDK-->>Frontend: validates customer domain and initialize
    end

    critical Unico journey exhibition
        Frontend->>SDK: byUnicoSDK.open
        SDK-->>Frontend: show byUnico experience
    end
    Note over SDK: User journey

    critical Unico journey completion
        SDK-->>Frontend: call onFinish
    end

    critical Get process result
        Frontend->>Backend: signals that journey was finished
        Backend->>Unico: call getProcess
        opt Webhook
            Note over Backend: In addition to getProcess, you can use the Webhook implementation to ensure a fallback in obtaining the process result.
        end
    end
```

#### 示例应用

| 语言 / 框架 | 描述 | 仓库 |
| --------------------- | ------------ | ---------- |
| Angular | 实现 Journeys SDK 的 Angular PoC | [GitHub — unico-cbu-poc-angular](https://github.com/unico-labs/unico-cbu-poc-angular) |
| JS Vanilla | 实现 Journeys SDK 的 JS Vanilla PoC | [GitHub — unico-cbu-poc-js](https://github.com/unico-labs/unico-cbu-poc-js) |
| React | 实现 Journeys SDK 的 React PoC | [GitHub — unico-cbu-poc-react](https://github.com/unico-labs/unico-cbu-poc-react) |
| Vue JS | 实现 Journeys SDK 的 Vue JS PoC | [GitHub — unico-cbu-poc-vuejs](https://github.com/unico-labs/unico-cbu-poc-vuejs) |

#### 安全性

:::note[本节适用范围]
此安全性说明专门适用于 **Web App Integration**（`idpay-b2b-sdk`）。**Web SDK**（`unico-webframe`）使用不同的模型：它完全在页面上下文中运行，并且[确实需要 CSP](/dual-api/developers/sdks-and-tools/web/web-sdk/installation)。这是两个具有不同安全架构的不同产品。
:::

该模型中的安全性是分层构建的，从 SDK 与在 iFrame 内部运行的应用程序之间的通信协议开始。

旅程加载时，双方会执行**握手（handshake）**以建立通信。在此过程中，Unico 应用程序会将通过 `postMessage` 接收到的数据注入消息的来源，与按环境（UAT 和 PROD）划分的授权域名封闭列表进行校验。来自未经批准来源的消息会被立即丢弃，从而防止旅程被嵌入到未经授权的页面中，并消除诸如**点击劫持（clickjacking）**等漏洞的攻击面。

除来源校验外，流程仅在持有有效交易令牌时才会继续：这是一个由 Unico 后端签发并签名的一次性 JWT。这确保了即使是已授权的来源，也无法使用已过期、被重复使用或被伪造的令牌进行操作。

握手完成后，令牌会被注入 iFrame，双方之间不再传输任何敏感信息。其余所有通信仅用于界面控制（打开、关闭和界面切换），从而防止流程数据在旅程期间被拦截或泄露。

iFrame 隔离还在运行时保护 Unico 脚本的完整性。由于代码在与页面分离的上下文中运行，外部脚本无法访问或修改它，从而确保旅程严格按照其构建方式运行，不受干扰。

按照设计，本集成模型不采用 CSP。授权域名是每个客户安全配置的一部分，将其在标头中公开可能会让恶意行为者更容易绘制基础设施的图谱。由于客户识别仅在 `init` 时才发生，因此无法在此之前将这些域名动态注入标头，这使得在不放弃此隐私性的前提下无法使用 CSP。所有安全保障均由上述握手协议提供。

#### SDK 专属故障排查

本节介绍集成过程中最常见的问题以及推荐的排查方法。

##### 意外行为或流程中断

请检查是否有应用程序脚本在 DOM 中直接操作 iFrame。SDK 在页面的 `body` 中创建并管理 iFrame，任何外部修改（无论是作用域、定位还是属性方面）都可能干扰旅程的生命周期并导致不可预测的行为。

##### 视觉体验与预期不符

请检查是否有应用程序的全局样式表覆盖了 iFrame 内部的属性。SDK 使用动态 ID 和以 `unico` 为前缀的类来创建 iFrame 及其所有内部元素，从而显著降低通过 ID 或类选择器产生冲突的风险。即便如此，作用域较广的 CSS 规则（例如标签选择器）仍可能触及 iFrame 内部的元素，并改变呈现给用户的视觉体验。

##### 直接修改了 SDK 库文件

请检查是否有库文件在依赖管理器之外被修改。该库必须仅通过 **npm** 或 **yarn** 管理，不得直接编辑已安装的文件。手动修改可能产生难以复现的异常行为，并使 Unico 支持无法提供协助。

#### 进行采集测试时请勿打开 DevTools

Unico 应用程序使用 Capture SDK（unico-webframe）进行人脸采集，它会将打开的 DevTools 检测为潜在的欺诈信号并阻止提交。运行端到端采集测试前请关闭 DevTools。

:::warning[不受支持的集成]
本文档中描述的模型（直接访问和 Journeys SDK）是 Unico 官方支持的唯一集成方式。偏离这些标准的集成可能导致意外行为、安全流程失败和旅程中断，并且不在 Unico 支持范围之内。

一些不受支持的方式示例：

- 在移动应用中**将 SDK 嵌入 WebView 内**。在这些情况下，正确的方式是使用**直接访问**模型，直接在 WebView 中打开旅程链接，而不涉及 Journeys SDK。
- 不经过 Journeys SDK，**直接通过 HTML `<iframe>` 标签加载 iFrame**。iFrame 是 SDK 的内部实现细节，不得手动实例化。正确的方式是使用 **Journeys SDK**，由它安全地、在预期标准范围内管理 iFrame 的生命周期。

如果对某种方式是否在受支持的标准范围内有任何疑问，请在继续实施之前查阅文档或联系支持团队。
:::