WEB3去中心化身份(DID)技术深度解析

引言 去中心化身份(Decentralized Identity,简称DID)是WEB3的核心基础设施之一。它让用户完全掌控自己的身份数据,不再依赖中心化的身份提供商。本文将深入探讨DID的技术原理、W3C标准、可验证凭证(VC)以及如何构建生产级的去中心化身份系统。 DID基础概念 传统身份系统的问题 中心化身份平台 ├── Google账号 │ └── 谷歌掌握所有数据 ├── 微信账号 │ └── 腾讯掌握所有数据 └── 支付宝账号 └── 蚂蚁掌握所有数据 问题: - 数据孤岛:各平台数据不互通 - 隐私泄露:中心化服务器易被攻击 - 审查风险:平台可随时封禁账号 - 数据滥用:平台可擅自使用用户数据 去中心化身份的优势 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // DID架构 interface DIDArchitecture { user: { control: "complete", // 用户完全控制 portable: true, // 身份可跨平台使用 privacy: "enhanced" // 隐私保护 }, verifier: { trust: "decentralized", // 去中心化信任 cost: "low" // 验证成本低 }, issuer: { efficiency: "high", // 发行效率高 revocation: "easy" // 撤销机制简单 } } W3C DID标准 DID结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // DID URL格式 did:method:specific-idstring // 示例 did:ethr:0x5a2e... // Ethereum DID did:sol:1234... // Solana DID did:web:example.com // Web DID did:key:z6Mk... // Key DID // 解析DID interface DID { method: string // 方法名(ethr, sol, web, key等) id: string // 特定方法的标识符 } DID文档 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 { "@context": [ "https://www.w3.org/ns/did/v1" ], "id": "did:ethr:0x5a2e...", "verificationMethod": [ { "id": "did:ethr:0x5a2e...#controller", "type": "EcdsaSecp256k1RecoveryMethod2020", "controller": "did:ethr:0x5a2e...", "blockchainAccountId": "0x5a2e...@eip155:1" } ], "authentication": [ "did:ethr:0x5a2e...#controller" ], "assertionMethod": [ "did:ethr:0x5a2e...#controller" ], "capabilityDelegation": [ "did:ethr:0x5a2e...#controller" ], "capabilityInvocation": [ "did:ethr:0x5a2e...#controller" ], "keyAgreement": [ { "id": "did:ethr:0x5a2e...#keyAgreement", "type": "X25519KeyAgreementKey2019", "controller": "did:ethr:0x5a2e...", "publicKeyBase58": "H3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" } ], "service": [ { "id": "did:ethr:0x5a2e...#vcs", "type": "VerifiableCredentialService", "serviceEndpoint": "https://example.com/vcs/" } ] } DID方法实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 // Ethereum DID Registry import { ethers } from 'ethers' class EthrDID { private registry: ethers.Contract private provider: ethers.Provider constructor() { this.provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com') this.registry = new ethers.Contract( '0xdca7ef03e98e0dc2b855be647c39abe984fcf21b', ['function owner(address) view returns (address)'], this.provider ) } async resolve(did: string): Promise<DIDDocument> { // 解析DID const [, , address] = did.split(':') // 从链上获取DID文档 const owner = await this.registry.owner(address) return { '@context': 'https://www.w3.org/ns/did/v1', id: did, verificationMethod: [{ id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `${address}@eip155:1` }], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`] } } async createDID(privateKey: string): Promise<string> { const wallet = new ethers.Wallet(privateKey) const address = await wallet.getAddress() return `did:ethr:${address}` } } // 使用 const ethrDid = new EthrDID() const did = await ethrDid.createDID(privateKey) // did:ethr:0x5a2e... const document = await ethrDid.resolve(did) 可验证凭证(Verifiable Credentials) VC数据模型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 interface VerifiableCredential { '@context': string[] | string type: string[] id?: string issuer: string | Issuer issuanceDate: string expirationDate?: string credentialSubject: CredentialSubject credentialStatus?: CredentialStatus refreshService?: RefreshService termsOfUse?: TermsOfUse[] evidence?: Evidence[] proof?: Proof } // 示例:大学学历凭证 const universityDegree: VerifiableCredential = { '@context': [ 'https://www.w3.org/2018/credentials/v1', 'https://www.w3.org/2018/credentials/examples/v1' ], type: ['VerifiableCredential', 'UniversityDegreeCredential'], id: 'urn:uuid:12345678-1234-5678-1234-567812345678', issuer: 'did:ethr:0x1234...', issuanceDate: '2024-01-06T12:00:00Z', expirationDate: '2034-01-06T12:00:00Z', credentialSubject: { id: 'did:ethr:0xabcd...', degree: { type: 'BachelorDegree', name: '计算机科学学士' }, university: '示例大学' }, proof: { type: 'EcdsaSecp256k1Signature2019', created: '2024-01-06T12:00:00Z', proofPurpose: 'assertionMethod', verificationMethod: 'did:ethr:0x1234...#controller', jws: 'eyJhbGciOiJFUzI1Nk...' // 签名 } } VC发行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 import { ethers } from 'ethers' import { createVerifiableCredentialJwt } from 'did-jwt-vc' class CredentialIssuer { private issuerDid: string private issuerWallet: ethers.Wallet constructor(did: string, privateKey: string) { this.issuerDid = did this.issuerWallet = new ethers.Wallet(privateKey) } async issueCredential( subjectDid: string, claims: object, expiresIn: string = '1y' ): Promise<string> { const vc: VerifiableCredential = { '@context': ['https://www.w3.org/2018/credentials/v1'], type: ['VerifiableCredential'], issuer: this.issuerDid, issuanceDate: new Date().toISOString(), expirationDate: new Date(Date.now() + this.parseExpiration(expiresIn)).toISOString(), credentialSubject: { id: subjectDid, ...claims } } // 创建签名 const signer = this.issuerWallet.signMessage.bind(this.issuerWallet) // 生成JWT格式的VC const vcJwt = await createVerifiableCredentialJwt( vc, { issuer: this.issuerDid, signer } ) return vcJwt } parseExpiration(expiresIn: string): number { const match = expiresIn.match(/^(\d+)([dhmy])$/) if (!match) throw new Error('Invalid expiration format') const value = parseInt(match[1]) const unit = match[2] const multipliers = { 'd': 86400000, 'h': 3600000, 'm': 60000, 'y': 31536000000 } return value * multipliers[unit] } } // 使用示例 const issuer = new CredentialIssuer( 'did:ethr:0x1234...', '0x私钥' ) const vcJwt = await issuer.issueCredential( 'did:ethr:0xabcd...', { degree: { type: 'BachelorDegree', name: '计算机科学学士' }, university: '示例大学' }, '1y' ) VC验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 import { verifyCredential, verifyPresentation } from 'did-jwt-vc' import { resolveDid } from '@identitybuilding/did-resolver' class CredentialVerifier { private didResolver: any constructor() { this.didResolver = resolveDid } async verifyCredential(vcJwt: string): Promise<VerificationResult> { try { // 验证签名 const verifiedVC = await verifyCredential(vcJwt, { resolver: this.didResolver }) // 检查过期 if (verifiedVC.expirationDate) { const expirationDate = new Date(verifiedVC.expirationDate) if (expirationDate < new Date()) { return { valid: false, reason: 'Credential has expired' } } } // 检查撤销状态 const status = await this.checkRevocation(verifiedVC) if (!status.valid) { return { valid: false, reason: 'Credential has been revoked' } } return { valid: true, credential: verifiedVC } } catch (error) { return { valid: false, reason: error.message } } } async checkRevocation(vc: VerifiableCredential): Promise<{ valid: boolean }> { if (!vc.credentialStatus) { return { valid: true } } const { id, type } = vc.credentialStatus if (type === 'RevocationList2021') { // 检查比特映射 const index = parseInt(id.split('#')[1]) const revoked = await this.checkBitMap(index) return { valid: !revoked } } return { valid: true } } async checkBitMap(index: number): Promise<boolean> { // 从链上或IPFS获取撤销列表 // ... return false } } // 使用示例 const verifier = new CredentialVerifier() const result = await verifier.verifyCredential(vcJwt) if (result.valid) { console.log('凭证有效', result.credential) } else { console.log('凭证无效:', result.reason) } VP(可验证表达) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 // Verifiable Presentation interface VerifiablePresentation { '@context': string[] | string type: string[] id?: string verifiableCredential?: VerifiableCredential[] holder?: string proof?: Proof } // 创建VP import { createVerifiablePresentationJwt } from 'did-jwt-vc' class PresentationHolder { private holderDid: string private holderWallet: ethers.Wallet constructor(did: string, privateKey: string) { this.holderDid = did this.holderWallet = new ethers.Wallet(privateKey) } async createPresentation( vcs: string[], audience: string ): Promise<string> { const vp: VerifiablePresentation = { '@context': ['https://www.w3.org/2018/credentials/v1'], type: ['VerifiablePresentation'], holder: this.holderDid, verifiableCredential: vcs.map(vcJwt => { // 简化版,实际应该解析JWT return { '@context': '...', type: ['VerifiableCredential'], ... } }) } const signer = this.holderWallet.signMessage.bind(this.holderWallet) const vpJwt = await createVerifiablePresentationJwt( vp, { audience, holder: this.holderDid, signer } ) return vpJwt } } // 使用 const holder = new PresentationHolder( 'did:ethr:0xabcd...', '0x用户私钥' ) const vpJwt = await holder.createPresentation( [vcJwt], 'did:ethr:0x9999...' // verifier的DID ) 链上身份协议 Lens Protocol 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 // Lens Profile NFT interface LensProfile { handle: string // @username imageURI: string // 头像 followModule: FollowModule followNFTURI: string dispatcher: Address } // 创建Lens Profile import { providers, Contract, utils } from 'ethers' class LensProfileManager { private lensHub: Contract private provider: providers.Provider constructor(rpcUrl: string) { this.provider = new providers.JsonRpcProvider(rpcUrl) this.lensHub = new Contract( '0xDb46d1Dc155634FfC7D94Fda11Bc2b0D29Ad869d', // LensHub on Polygon [ 'function createProfile(tuple(tuple(string handle,string imageURI) profile)) external', 'function getDefaultProfile(address) view returns (uint256)', 'function getProfile(uint256) view returns (tuple(...))' ], new ethers.Wallet(process.env.PRIVATE_KEY, this.provider) ) } async createProfile(handle: string, imageURI: string): Promise<string> { const tx = await this.lensHub.createProfile({ profile: { handle, imageURI } }) const receipt = await tx.wait() console.log('Profile created:', receipt.transactionHash) return receipt.transactionHash } async getProfile(profileId: number): Promise<LensProfile> { const profile = await this.lensHub.getProfile(profileId) return { handle: profile.handle, imageURI: profile.imageURI, followModule: profile.followModule, followNFTURI: profile.followNFTURI, dispatcher: profile.dispatcher } } } // 使用 const lens = new LensProfileManager('https://polygon-rpc.com') await lens.createProfile( 'myusername', 'ipfs://Qm...' ) ENS (Ethereum Name Service) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 import { providers, Contract } from 'ethers' class ENSManager { private ensRegistry: Contract private resolverContract: Contract private provider: providers.Provider constructor(rpcUrl: string) { this.provider = new providers.JsonRpcProvider(rpcUrl) // ENS Registry this.ensRegistry = new Contract( '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e', ['function owner(bytes32 node) view returns (address)'], this.provider ) // Public Resolver this.resolverContract = new Contract( '0x4976fb03C32e5B8cfe2b6cCCb85c41a121551E2F', [ 'function addr(bytes32 node) view returns (address)', 'function setText(bytes32 node, string key, string value)', 'function text(bytes32 node, string key) view returns (string)' ], this.provider ) } namehash(name: string): string { // ENS namehash算法 const node = '0x0000000000000000000000000000000000000000000000000000000000000000' if (name === '') { return node } const labels = name.split('.') let hash = node for (let i = labels.length - 1; i >= 0; i--) { const labelHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(labels[i])) hash = ethers.utils.keccak256( ethers.utils.concat([hash, labelHash]) ) } return hash } async getAddress(name: string): Promise<string> { const node = this.namehash(name) return await this.resolverContract.addr(node) } async setText(name: string, key: string, value: string, signer: ethers.Signer) { const node = this.namehash(name) const resolverWithSigner = this.resolverContract.connect(signer) const tx = await resolverWithSigner.setText(node, key, value) await tx.wait() } async getText(name: string, key: string): Promise<string> { const node = this.namehash(name) return await this.resolverContract.text(node, key) } } // 使用 const ens = new ENSManager('https://eth.llamarpc.com') // 解析ENS域名 const address = await ens.getAddress('vitalik.eth') // 0xab5801a7D398351b8bE11C439e05C5B3259aEbC4 // 设置和读取ENS记录 await ens.setText( 'mydomain.eth', 'com.twitter', '@myhandle', signer ) Soulbound Token (SBT) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 // SBT(灵魂绑定代币)是不可转移的NFT import { ethers } from 'ethers' // SBT合约ABI const SBT_ABI = [ 'function issue(address to, uint256 tokenId, string uri) external', 'function revoke(address from, uint256 tokenId) external', 'function tokenURI(uint256 tokenId) view returns (string)', 'function balanceOf(address) view returns (uint256)', 'function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)' ] class SoulboundManager { private sbtContract: ethers.Contract constructor(contractAddress: string, privateKey: string) { const provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com') const wallet = new ethers.Wallet(privateKey, provider) this.sbtContract = new ethers.Contract( contractAddress, SBT_ABI, wallet ) } async issueSBT( recipient: string, tokenId: number, metadataURI: string ): Promise<string> { const tx = await this.sbtContract.issue( recipient, tokenId, metadataURI ) const receipt = await tx.wait() return receipt.transactionHash } async getSBTsByAddress(address: string): Promise<number[]> { const balance = await this.sbtContract.balanceOf(address) const tokens = [] for (let i = 0; i < balance.toNumber(); i++) { const tokenId = await this.sbtContract.tokenOfOwnerByIndex(address, i) tokens.push(tokenId.toNumber()) } return tokens } async getSBTMetadata(tokenId: number): Promise<object> { const uri = await this.sbtContract.tokenURI(tokenId) // 从IPFS获取metadata const response = await fetch(uri) const metadata = await response.json() return metadata } } // 使用示例 const sbtManager = new SoulboundManager( '0x...', // SBT合约地址 process.env.PRIVATE_KEY ) // 发行SBT凭证 await sbtManager.issueSBT( '0x用户地址', 1, 'ipfs://Qm...' // metadata URI ) // 查询用户的SBT const tokens = await sbtManager.getSBTsByAddress('0x用户地址') for (const tokenId of tokens) { const metadata = await sbtManager.getSBTMetadata(tokenId) console.log('SBT:', metadata) // { // name: "大学学历凭证", // description: "计算机科学学士学位", // image: "ipfs://...", // attributes: [ // { trait_type: "大学", value: "示例大学" }, // { trait_type: "专业", value: "计算机科学" }, // { trait_type: "学位", value: "学士" } // ] // } } 链上声誉系统 信任分数算法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 interface ReputationData { totalInteractions: number successfulInteractions: number averageRating: number stakingAmount: number accountAge: number } class ReputationCalculator { calculateScore(data: ReputationData): number { let score = 50 // 基础分 // 交互成功率(+30分) if (data.totalInteractions > 0) { const successRate = data.successfulInteractions / data.totalInteractions score += successRate * 30 } // 平均评分(+10分) score += (data.averageRating - 3) * 3.33 // 1-5分制 // 质押金额(+5分) const stakingBonus = Math.log10(data.stakingAmount + 1) * 2 score += Math.min(stakingBonus, 5) // 账号年龄(+5分) const ageInYears = data.accountAge / (365 * 24 * 60 * 60) score += Math.min(ageInYears * 2, 5) return Math.min(Math.max(score, 0), 100) } calculateTier(score: number): string { if (score >= 90) return '钻石级' if (score >= 75) return '黄金级' if (score >= 60) return '白银级' if (score >= 40) return '青铜级' return '新手级' } } // 链上声誉合约 import { ethers } from 'ethers' class OnChainReputation { private contract: ethers.Contract constructor() { const provider = new ethers.JsonRpcProvider('https://polygon-rpc.com') const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider) this.contract = new ethers.Contract( '0x...', // 声誉合约地址 [ 'function recordInteraction(address user, bool success, uint8 rating) external', 'function getReputationScore(address user) view returns (uint256)', 'function stakeTokens(uint256 amount) external', 'function unstakeTokens(uint256 amount) external', 'event ReputationUpdated(address indexed user, uint256 score)' ], wallet ) } async recordInteraction( user: string, success: boolean, rating: number ): Promise<void> { const tx = await this.contract.recordInteraction( user, success, rating ) await tx.wait() console.log('Interaction recorded') } async getReputationScore(user: string): Promise<number> { const score = await this.contract.getReputationScore(user) return score.toNumber() } async stakeTokens(amount: number): Promise<void> { const tx = await this.contract.stakeTokens( ethers.utils.parseEther(amount.toString()) ) await tx.wait() console.log('Tokens staked') } listenToReputationUpdates() { this.contract.on('ReputationUpdated', (user, score) => { console.log(`Reputation updated for ${user}: ${score}`) }) } } DID钱包实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 import { ethers } from 'ethers' import { hdkey } from 'ethereumjs-wallet' import * as bip39 from 'bip39' class DIDWallet { private mnemonic: string private hdNode: any private did: string private credentials: string[] = [] constructor() { this.generate() } private generate() { // 生成助记词 this.mnemonic = bip39.generateMnemonic() // 从助记词生成HD钱包 const seed = bip39.mnemonicToSeedSync(this.mnemonic) this.hdNode = hdkey.fromMasterSeed(seed) // 派生第一个账户作为DID const path = "m/44'/60'/0'/0/0" const wallet = this.hdNode.derivePath(path).getWallet() const address = wallet.getAddressString() this.did = `did:ethr:${address}` } getDID(): string { return this.did } getAddress(): string { return this.did.split(':')[2] } async sign(message: string): Promise<string> { const path = "m/44'/60'/0'/0/0" const wallet = this.hdNode.derivePath(path).getWallet() const signature = await wallet.signMessage(message) return signature } async verify(message: string, signature: string): Promise<boolean> { const address = ethers.utils.verifyMessage(message, signature) return address.toLowerCase() === this.getAddress().toLowerCase() } addCredential(vcJwt: string) { this.credentials.push(vcJwt) } getCredentials(): string[] { return this.credentials } exportWallet(): string { return JSON.stringify({ mnemonic: this.mnemonic, did: this.did, credentials: this.credentials }) } importWallet(data: string) { const wallet = JSON.parse(data) this.mnemonic = wallet.mnemonic this.did = wallet.did this.credentials = wallet.credentials || [] const seed = bip39.mnemonicToSeedSync(this.mnemonic) this.hdNode = hdkey.fromMasterSeed(seed) } } // React Hook import { useState, useEffect } from 'react' export function useDIDWallet() { const [wallet, setWallet] = useState<DIDWallet | null>(null) useEffect(() => { // 从localStorage加载钱包 const savedWallet = localStorage.getItem('did-wallet') if (savedWallet) { const newWallet = new DIDWallet() newWallet.importWallet(savedWallet) setWallet(newWallet) } else { // 创建新钱包 const newWallet = new DIDWallet() setWallet(newWallet) // 保存到localStorage localStorage.setItem('did-wallet', newWallet.exportWallet()) } }, []) const backupWallet = () => { if (wallet) { const data = wallet.exportWallet() const blob = new Blob([data], { type: 'application/json' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `did-wallet-${Date.now()}.json` a.click() } } return { wallet, backupWallet } } 完整DID应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 import { useState } from 'react' import { DIDWallet } from './did-wallet' import { CredentialIssuer } from './credential-issuer' import { CredentialVerifier } from './credential-verifier' export default function DIDApp() { const [wallet] = useState(() => new DIDWallet()) const [credentials, setCredentials] = useState<string[]>([]) const [presentation, setPresentation] = useState<string>('') const issueCredential = async (claims: object) => { const issuer = new CredentialIssuer( wallet.getDID(), '0x...' // 发行方私钥 ) const vcJwt = await issuer.issueCredential( wallet.getDID(), claims ) setCredentials([...credentials, vcJwt]) } const createPresentation = async () => { const holder = new PresentationHolder( wallet.getDID(), '0x...' // 用户私钥 ) const vpJwt = await holder.createPresentation( credentials, 'did:ethr:0x9999...' // verifier DID ) setPresentation(vpJwt) } const verifyPresentation = async (vpJwt: string) => { const verifier = new CredentialVerifier() const result = await verifier.verifyPresentation(vpJwt) return result } return ( <div> <h1>DID身份钱包</h1> <div> <h2>我的DID</h2> <p>{wallet.getDID()}</p> </div> <div> <h2>凭证</h2> {credentials.map((vc, index) => ( <div key={index}> <pre>{vc}</pre> </div> ))} </div> <div> <h2>可验证表达</h2> <pre>{presentation}</pre> </div> <button onClick={() => issueCredential({ name: '张三' })}> 发行凭证 </button> <button onClick={createPresentation}> 创建表达 </button> </div> ) } 总结 去中心化身份(DID)是WEB3的重要基础设施,通过W3C标准化、区块链技术和密码学,为用户提供了真正自主可控的身份系统。 ...