WalletHandlers 类是一个高级实用工具,旨在将 DID Connect 工作流无缝集成到 Express.js 或类似的服务器端框架中。它能为给定操作自动设置所有必需的 API 端点,处理您的应用程序与用户的 DID Wallet 之间的通信。
它与 WalletAuthenticator 协同工作,后者负责管理消息的加密签名和验证。由于 WalletHandlers 构建于 Node.js 的 EventEmitter 之上,您可以监听会话状态在令牌存储中变化时的各种生命周期事件。
构造函数
创建 DID Connect 处理程序的实例。该实例负责协调处理 DID Connect 过程中的 HTTP 请求。
DID Connect Handler Setup
const { WalletHandlers } = require('@did-connect/handler');
const { WalletAuthenticator } = require('@did-connect/authenticator');
const { FileStorage } = require('@did-connect/storage-file');
// 1. 使用您的应用程序的钱包和信息初始化身份验证器
const authenticator = new WalletAuthenticator({ wallet, appInfo, chainInfo });
// 2. 初始化存储适配器以管理会话状态
const tokenStorage = new FileStorage({ dbPath: './sessions.json' });
// 3. 创建处理程序实例
const handlers = new WalletHandlers({
authenticator,
tokenStorage,
});参数
- config
object(required) — WalletHandlers 实例的配置对象。- authenticator
WalletAuthenticator(required) — 一个负责加密操作的WalletAuthenticator实例。 - tokenStorage
object(required) — 一个处理会话状态的令牌存储实例(例如FileStorage、MongoStorage)。 - pathTransformer
function— 一个可选函数,用于转换钱包回调的 URL 路径名,在代理或复杂路由场景中很有用。 - onConnect
function— 一个可选的全局回调函数,在钱包扫描二维码后、身份验证请求发送前执行。它可用于全局权限检查。抛出错误可中止该过程。 - options
object— 一个可选对象,用于自定义处理程序的行为。- prefix
string(default:/api/did) — 所有生成端点的 URL 前缀。 - cleanupDelay
number(default:60000) — 从存储中清理已完成会话前等待的时间(毫秒)。 - tokenKey
string(default:_t_) — 会话令牌的查询参数键。 - encKey
string(default:_ek_) — 加密密钥的查询参数键。 - versionKey
string(default:_v_) — 协议版本的查询参数键。
- prefix
- authenticator
方法
attach(config)
这是 WalletHandlers 类的主要方法。它为特定的用户操作(例如‘登录’、‘支付’)将必要的 DID Connect 路由附加到您的 Express 应用程序。此方法创建一整套端点来处理整个连接生命周期,从令牌生成到钱包响应处理。
附加后,将为给定的 action 创建以下路由:
GET {prefix}/{action}/token: 创建一个新的会话令牌。POST {prefix}/{action}/token: 创建一个新的会话令牌。GET {prefix}/{action}/status: 检查会话令牌的状态(例如,等待中、已扫描、已批准)。GET {prefix}/{action}/timeout: 手动使会话令牌过期。GET {prefix}/{action}/auth: 钱包获取身份验证要求的端点。POST {prefix}/{action}/auth: 钱包提交签名响应的端点。
参数
- config
object(required) — 用于附加路由的配置对象。- app
object(required) — Express 应用程序实例。 - action
string(required) — 此工作流的唯一名称(例如,‘login’、‘claim-asset’)。这将成为 URL 的一部分。 - onAuth
function(required) — 用户在钱包中成功完成流程后执行的回调。您在此处处理已验证的数据。 - claims
object[]— 一个可选的声明数组,用于向用户请求信息(例如,个人资料、签名)。 - onStart
function— 一个可选的回调函数,在新会话启动时执行。 - onConnect
function— 一个可选的回调函数,在钱包扫描二维码时执行。它会为此特定操作覆盖构造函数中的onConnect。 - onDecline
function— 一个可选的回调函数,如果用户在钱包中拒绝请求,则执行该回调。 - onComplete
function— 一个可选的回调函数,在整个工作流完成且会话令牌被销毁后执行。 - onExpire
function— 一个可选的回调函数,用于会话令牌过期时。 - onError
function(default:console.error) — 一个可选的回调函数,用于处理过程中的任何错误。 - authPrincipal
boolean | string(default:true) — 是否首先请求authPrincipal声明以确定用户的 DID。 - persistentDynamicClaims
boolean(default:false) — 是否在会话存储中持久化动态生成的声明。
- app
示例
Attach Login Handler
const express = require('express');
// ... 从构造函数示例中设置身份验证器和令牌存储
const app = express();
const handlers = new WalletHandlers({ authenticator, tokenStorage });
handlers.attach({
app,
action: 'login',
claims: [{ type: 'profile' }], // 请求用户的个人资料
onAuth: async ({ userDid, claims }) => {
// 成功登录后的核心逻辑。
// 使用 userDid 在您的数据库中查找或创建用户。
const profile = claims.find(x => x.type === 'profile');
console.log(`用户 ${userDid} 已登录,用户名为: ${profile.fullName}。`);
// 现在您可以为用户的 Web 会话设置 cookie 或 JWT。
},
onComplete: ({ token }) => {
console.log(`会话 ${token} 已完成并清理。`);
},
onError: ({ error }) => {
console.error('登录流程中发生错误:', error);
}
});
app.listen(3000, () => {
console.log('DID Connect 服务器正在端口 3000 上运行');
});事件
由于 WalletHandlers 继承自 EventEmitter 并监听 tokenStorage 实例,您可以订阅事件来监控会话的生命周期。这对于向用户提供实时反馈特别有用,例如,通过使用 WebSockets 在扫描二维码时更新 UI。
| Event | Payload | Description |
|---|---|---|
created | object | 当创建新会话令牌时发出。负载包含令牌和初始会话数据。 |
updated | object | 当会话更新时发出。负载包含更新后的会话数据。一个常见的用途是检查 status: 'scanned'。 |
deleted | object | 当会话令牌被销毁时发出,无论是在完成、过期还是手动超时的情况下。负载包含被移除的令牌。 |
示例
Listening to Session Events
// 假设 'io' 是附加到您的 Express 应用程序的 Socket.IO 服务器实例
handlers.on('updated', (payload) => {
// 通知特定的 Web 客户端二维码已被扫描
if (payload.status === 'scanned') {
console.log(`钱包已扫描令牌: ${payload.token}`);
// 'sid' (socket ID) 应在会话创建时存储在会话中
if (payload.sid) {
io.to(payload.sid).emit('wallet_scanned');
}
}
});
handlers.on('deleted', ({ token }) => {
console.log(`令牌 ${token} 已从存储中删除。`);
});