Web App 集成
本页介绍 Unico 旅程的工作方式,以及可用于将其集成到应用程序中的集成模型。
旅程是用户为完成身份验证而经历的一系列步骤。例如:拍摄证件照片和进行人脸采集(活体检测)。
Unico 负责管理整个体验。集成所需的工作量极小:旅程通过 CreateProcess 创建,用户被引导至该旅程,并在最后接收结果。中间发生的一切(界面、提示、校验)都已构建完成并由 Unico 维护。
- 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 应用 |
- 直接访问
- Journeys SDK
用户被重定向到由 Unico 托管的链接,旅程在该处进行。完成后,用户会返回到创建流程时定义的 URL(callbackUri 参数)。
这是最易于采用的方式:无需安装任何库,并且在旅程不需要发生在应用程序自身页面内时效果良好。另一方面,将用户带离客户的环境往往会带来更多摩擦,从而导致更高的流失率。
创建流程后,API 响应中会包含由 Unico 托管的旅程 URL。有两种常见的方式可将用户引导至该 URL:
- 标准重定向。 用户被直接重定向到旅程 URL。完成后,Unico 会将其重定向回创建流程时定义的
callbackUri。 - 使用
window.open()打开新标签页。 旅程在新的浏览器标签页中打开,使用户保持在独立的上下文中。在这种情况下,建议监听 URL 变化为callbackUri,并在流程完成后关闭标签页。有关该 API 的详细信息,请参阅 MDN 文档。

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

旅程在应用程序自身内部进行,不会让用户离开其上下文。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 类。
npm install idpay-b2b-sdk
安装 Journeys SDK 的推荐方式是通过 npm 或 yarn 等依赖管理器,从 npm registry 上提供的包进行安装。这种方式不仅简化了安装和依赖管理,还能清晰地控制所使用的版本,并便于在每次发布新版本时进行更新。
SDK 遵循语义化版本控制(SemVer),这意味着 patch 和 minor 更新不会引入破坏性变更。可以安全地将项目配置为自动接收这些更新。可能需要调整集成的变更会保留给 major 版本,并始终附带迁移指南。
保持最新版本之所以特别重要,有两个原因。第 一是安全性:每当发现漏洞或出现加强通信协议的机会时,都会发布安全补丁。运行过时的版本意味着放弃这些修复,并使流程暴露于不必要的风险之中。第二是稳定性:错误修复也以相同方式分发,旧版本可能存在在较新版本中已解决的行为。
开始之前,请向 Unico 支持团队注册你的域名。所有域名都必须使用 HTTPS。
步骤 2:调用 init(options)
初始化 SDK 并预加载旅程正确运行所需的脚本,为最终用户带来更流畅的体验。请在流程中尽早调用它。
| 参数 | 必填 | 说明 |
|---|---|---|
token | 是 | Create Process API 返回的流程令牌 |
env | 否 | 仅在测试环境中设置为 'uat' |
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 来处理应用程序的前端状态:
- 避免循环。 防止在旅程结束后用户立即再次触发流程时,进程被立即且不必要地重新创建。
- 流程管理。 确保用户被引导至应用程序的下一步,避免在旅程关闭后停留在无法退出的界面上。
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,则可以放心地省略它。
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:

安全性
此安全性说明专门适用于 Web App Integration(idpay-b2b-sdk)。Web SDK(unico-webframe)使用不同的模型:它完全在页面上下文中运行,并且确实需要 CSP。这是两个具有不同安全架构的不同产品。
该模型中的安全性是分层构建的,从 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。
本文档中描述的模型(直接访问和 Journeys SDK)是 Unico 官方支持的唯一集成方式。偏离这些标准的集成可能导致意外行为、安全流程失败和旅程中断,并且不在 Unico 支持范围之内。
一些不受支持的方式示例:
- 在移动应用中将 SDK 嵌入 WebView 内。在这些情况下,正确的方式是使用直接访问模型,直接在 WebView 中打开旅程链接,而不涉及 Journeys SDK。
- 不经过 Journeys SDK,直接通过 HTML
<iframe>标签加载 iFrame。iFrame 是 SDK 的内部实现细节,不得手动实例化。正确的方式是使用 Journeys SDK,由它安全地、在预期标准范围内管理 iFrame 的生命周期。
如果对某种方式是否在受支持的标准范围内有任何疑问,请在继续实施之前查阅文档或联系支持团队。