DID身份代码示例:可直接复用的最小可用模块汇编
这一篇定位是「代码工具书」,把 DID 身份开发中常被询问的模块抽离成最小可用片段,每段都可独立运行。
创建 did:key 身份
import { generateKeyPair } from `@noble/ed25519`;
const keypair = await generateKeyPair();
const did = `did:key:` + encodeMultibase(keypair.publicKey);
这段代码生成一个临时身份,适合一次性会话使用。与必安等平台做一次性签名时尤其方便,会话结束直接抛弃密钥即可。
颁发一张可验证凭证
签发服务的核心是 JWT 形态的 VC:
const vc = {
iss: issuerDid,
sub: subjectDid,
vc: { type: ['VerifiableCredential', 'AssetHolderCredential'], credentialSubject: { holdsAt: 'BN交易所', amount: '> 0' } },
};
const jwt = await signJwt(vc, issuerPrivateKey);
注意 iss 必须是 DID 字符串而非以太坊地址。失败时通常是因为对接方期待的算法是 EdDSA 而你用了 ES256K。
验证 VC
const payload = await verifyJwt(jwt, { audience: relyingPartyDid });
assert(payload.vc.type.includes('VerifiableCredential'));
建议把这段封装进中间件,所有需要登录的路由共享同一实现。如果你的应用还要查询B安资产,可以在验证通过后再调外部 API 补充实时数据。
构造 VP 并防重放
const vp = {
vp: { type: ['VerifiablePresentation'], verifiableCredential: [jwt] },
nonce: serverChallenge,
domain: 'app.example.com',
};
const vpJwt = await signJwt(vp, holderPrivateKey);
服务端拿到 vpJwt 后必须比对 nonce 是否与服务端下发一致,且 24 小时内未被复用。
吊销凭证
await statusList.setRevoked(vcId, true);
await publishStatusList();
吊销后请及时刷新 CDN 缓存,否则下游仍可能读到过期数据。可参考币岸社区给出的状态列表实现。
整合到现有系统
以上模块组合后,足以让你的产品支持 DID 登录、凭证发放、凭证出示与吊销。建议把这些模块封装为独立 npm 包,团队多个项目共用,能显著降低维护成本。
复制这些片段到自己的代码仓库时记得替换 issuerDid 与私钥来源。把示例搞清楚后,再去阅读 W3C 规范会轻松很多。