正如 请求声明 指南所示,在为 DID Connect 会话定义声明后,下一个关键步骤是处理来自用户 DID 钱包的响应。@arcblock/did-connect-js 库提供了一套全面的生命周期回调,用于管理会话的每一种可能结果,无论用户是批准、拒绝还是会话超时。
这些回调作为函数传递给 handlers.attach() 方法,为您提供切入身份验证流程的特定挂钩,以运行您的业务逻辑。
DID Connect 生命周期
一个典型的 DID Connect 会话遵循一个清晰的事件序列。下图说明了此流程,并指出了每个主要生命周期回调的触发时机。

生命周期回调
以下是可用于处理整个 DID Connect 会话生命周期的回调的详细说明。
| 回调 | 触发时机... | 常见用例 |
|---|---|---|
onStart | 新会话已启动且二维码已准备就绪。 | 记录会话启动,准备会话特定资源。 |
onConnect | 用户的钱包扫描二维码并建立连接,但在声明被批准之前。 | 基于 userDid 进行权限检查,生成动态声明。 |
onDecline | 用户在钱包中明确拒绝请求。 | 显示取消信息,记录拒绝操作。 |
onAuth | (必需) 用户批准请求并提交所请求的声明。 | 核心业务逻辑: 验证声明、创建用户会话、更新数据库。 |
onComplete | 整个 DID Connect 会话已结束,无论成功与否。 | 最终清理任务,移除临时会话数据。 |
onExpire | 在用户完成操作前会话超时。 | 通知用户二维码已过期,清理过时会话。 |
onError | 会话期间发生意外错误。 | 错误记录和报告。 |
onConnect:预批准逻辑与动态声明
The onConnect 回调功能强大,因为它允许你在获知用户 DID 但在用户看到完整声明列表之前运行逻辑。这是执行权限检查或根据用户身份动态生成声明的理想时机。
参数: { req, challenge, userDid, userPk, extraParams, updateSession }
示例:使用 onConnect 生成动态声明
handlers.attach({
action: 'dynamic-claims',
// 此函数可以是异步的
onConnect: ({ userDid }) => {
// 你可以根据白名单检查用户的 DID
if (!isUserAllowed(userDid)) {
throw new Error('你无权访问此服务。');
}
// 或者根据用户属性返回一组动态声明
return {
profile: () => ({
fields: ['fullName', 'email'],
description: '请提供你的姓名和电子邮件以继续',
}),
};
},
onAuth: async ({ claims, userDid }) => {
// `claims` 现在包含动态生成的个人资料声明的结果
console.log('动态声明已由以下用户批准:', userDid, claims);
},
});onAuth:处理成功认证
The onAuth 回调是 DID Connect 集成的核心。它是唯一必需的回调,在用户于钱包中成功批准请求时执行。它会接收到用户提交的声明数据,你可以利用这些数据来完成应用程序的逻辑,例如让用户登录或验证资产所有权。
参数: { req, challenge, claims, userDid, userPk, extraParams, updateSession }
示例:在 onAuth 中处理提交的声明
handlers.attach({
action: 'profile-login',
claims: {
profile: () => ({
fields: ['fullName', 'email'],
description: '请提供你的姓名和电子邮件以登录。',
}),
},
onAuth: async ({ userDid, claims }) => {
try {
const profileClaim = claims.find((c) => c.type === 'profile');
if (profileClaim) {
console.log(`用户 ${userDid} 登录成功`);
console.log('用户资料:', profileClaim.value);
// 在这里,你通常会创建一个用户会话,保存到数据库等。
const user = await findOrCreateUser(userDid, profileClaim.value);
}
} catch (err) {
console.error('登录过程中出错:', err);
}
},
});onDecline:处理用户取消操作
如果用户决定在钱包中取消请求,onDecline 回调就会被触发。这使你能够优雅地处理取消操作,例如,在前端通知用户登录尝试已被取消。
参数: { req, challenge, userDid, userPk, extraParams, updateSession }
示例:处理被拒绝的请求
handlers.attach({
action: 'profile-login',
claims: { /* ... */ },
onAuth: async ({ userDid, claims }) => { /* ... */ },
onDecline: ({ userDid }) => {
console.log(`用户 ${userDid} 拒绝了连接请求。`);
// 你可以更新会话以通知前端
},
});使用 updateSession 持久化数据
包括 onAuth、onConnect 和 onStart 在内的多个回调都会接收一个 updateSession 函数作为参数。这个工具对于将信息从后端逻辑传递回会话状态至关重要,然后前端应用程序可以轮询并检索这些信息。
例如,在 onAuth 中成功登录后,你可以生成一个特定于应用程序的 JWT 并将其保存到会话中。你的前端随后可以检索此令牌来认证后续的 API 请求。
- 持久化普通的、非敏感信息:
await updateSession({ key: 'value' }); - 持久化敏感信息(将被加密):
await updateSession({ key: 'sensitive-value' }, true);
示例:使用 updateSession 将令牌传递给前端
handlers.attach({
action: 'profile-login',
claims: { /* ... */ },
onAuth: async ({ userDid, claims, updateSession }) => {
const user = await findOrCreateUser(userDid, claims);
const appToken = generateAppToken(user);
// 持久化一个非敏感的会话 ID
await updateSession({ sessionId: 'some-session-id' });
// 持久化一个敏感的 JWT,它将在会话存储中被加密
await updateSession({ token: appToken }, true);
console.log(`用户 ${userDid} 的会话已更新`);
},
});通过有效利用这些生命周期回调,你可以构建稳健且用户友好的身份验证流程。既然你已经了解了如何处理单个会话的响应,就可以开始探索更复杂的用户旅程。
接下来,请在 链接工作流 指南中学习如何通过将多个 DID Connect 会话链接在一起来创建多步骤交互。