跳到主要内容

链接工作流

DID Connect 允许你将多个不同的身份验证会话链接在一起,通过一次初始交互为用户创建一个无缝的多步骤流程。这对于复杂的场景非常理想,例如用户注册后进行 KYC,或者登录后进行交易确认。

本指南解释了链接工作流背后的机制以及如何在它们之间传递数据。

核心机制

链接工作流的关键在于 onAuth 生命周期回调。当 DID Connect 会话中的一个步骤成功完成后,onAuth 处理程序不是简单地结束会话,而是可以启动一个新的会话,并指示用户的钱包自动进入该会话。

这是通过从 onAuth 函数返回两个特定属性来实现的:

  • nextWorkflow:下一个 DID Connect 会话的完整深层链接 URL。
  • nextToken:下一个工作流的会话令牌。

当钱包收到包含 nextWorkflow 的响应时,它会立即打开此 URL,开始流程的下一个阶段,而无需用户扫描新的二维码。原始会话保持待定状态,直到整个工作流链完成或被拒绝。

会话完成的工作原理

当你将会话 A 链接到会话 B 时:

  1. 会话 A 的 onAuth 返回会话 B 的 nextWorkflownextToken
  2. 会话 A 不会被标记为 succeed。相反,它会记录它已被会话 B 接替。
  3. 当会话 B(链中的最终会话)成功完成时,它会将自己标记为 succeed
  4. 然后它会查找 prevToken(会话 A 的令牌)并将该会话也标记为 succeed,从而确保整个链被正确关闭。

Chaining Workflows

在工作流之间传递数据

通常,你需要将上下文从一个步骤传递到下一个步骤。例如,将用户的 DID 从登录步骤传递到后续的购买步骤。这可以通过使用 nextWorkflowDatapreviousWorkflowData 来实现。

  1. 发送数据

    在第一个会话的 onAuth 处理程序中,返回一个名为 nextWorkflowData 的对象。该对象将被自动进行 Base64 编码,并作为 previousWorkflowData 查询参数附加到 nextWorkflow URL 中。

  2. 接收数据

    下一个会话将自动解析此参数。解码后的数据将在该会话的所有生命周期钩子(onStartonConnectonAuth)内的 extraParams.previousWorkflowData 对象中可用。

如果你链接了两个以上的工作流(A → B → C),数据会被合并。当会话 B 返回自己的 nextWorkflowData 时,它会与从 A 收到的 previousWorkflowData 合并,然后将合并后的对象传递给 C。

实现示例

让我们考虑一个场景:用户登录后,立即被提示签署一条欢迎消息。

步骤 1:定义登录工作流

在你的登录会话的 onAuth 处理程序中,你将为签署消息生成一个新会话,并将其作为 nextWorkflow 返回。

login-handler.js

javascript
// 这是一个简化的示例。在实际应用中,你将有一个单独的端点来生成令牌。
const { WalletHandlers, WalletAuthenticator } = require('@arcblock/did-connect');
const get = require('lodash/get');

// 假设 authenticator 和 tokenStorage 已初始化
const authenticator = new WalletAuthenticator(/* ... */);
const tokenStorage = new MemoryAuthStorage();

const handlers = new WalletHandlers({ authenticator, tokenStorage });

// 第一步的处理程序:登录
handlers.attach({
  app: server,
  action: 'login',
  claims: { profile: { description: '请提供你的个人资料' } },
  onAuth: async ({ userDid, claims }) => {
    const profile = claims.find(x => x.type === 'profile');
    console.log(`名为 ${profile.fullName} 的 ${userDid} 已登录。`);

    // 现在,为签署消息创建下一个工作流
    // 在实际应用中,你会调用自己的令牌生成端点
    const { data: nextSession } = await axios.get('https://yourapp.com/api/did/sign/token');

    return {
      // 下一个会话的 URL 和令牌
      nextWorkflow: nextSession.url,
      nextToken: nextSession.token,
      // 将用户名传递给下一步
      nextWorkflowData: {
        fullName: profile.fullName,
      },
    };
  },
});

步骤 2:定义签名工作流

此工作流将从登录步骤接收用户名,并用它来自定义签名请求。

sign-handler.js

javascript
// 第二步的处理程序:签署消息
handlers.attach({
  app: server,
  action: 'sign',
  claims: {
    signature: ({ extraParams }) => {
      // 从上一个工作流访问数据
      const fullName = get(extraParams, 'previousWorkflowData.fullName', 'user');
      return {
        type: 'mime:text/plain',
        description: `你好 ${fullName},请签署这条欢迎消息!`,
        data: `欢迎加入,${fullName}!`,
      };
    },
  },
  onAuth: async ({ userDid }) => {
    console.log(`${userDid} 签署了欢迎消息。`);
    // 这是最后一步,所以我们不返回 nextWorkflow
    return { successMessage: '入门流程完成!' };
  },
});

通过此设置,用户扫描一个二维码进行登录,批准后,其钱包中会立即显示个性化的签名请求。签名后,整个多步骤过程即告完成。

链接工作流是设计复杂且用户友好的交互的强大功能。你可以创建复杂的入门流程、多方协议或任何需要顺序、经过身份验证的步骤的流程。

接下来,了解另一个用于更复杂应用程序结构的高级功能。请参阅 Delegated Connect 指南。