去中心化身份:2025年Web3身份验证系统开发实践

去中心化身份:2025年Web3身份验证系统开发实践

当你在传统互联网上创建账户时,数据被锁定在特定平台上。Facebook知道你的社交关系,Google掌握你的搜索习惯,银行控制着你的金融身份。但如果告诉你,有一种技术能让你真正拥有自己的数字身份,不再受制于任何中心化服务商呢?

这就是去中心化身份(Decentralized Identity,DID)要解决的核心问题。随着Web3生态的快速发展,传统的"用户名+密码"身份验证模式已经无法满足去中心化应用的需求。用户需要一个既安全又便携的身份系统,能够在不同的dApp之间无缝切换,同时保持对个人数据的完全控制权。

在2025年,DID不再是概念验证,而是成熟的技术解决方案。本文将深入解析如何构建一个完整的Web3身份验证系统,从底层的密码学原理到用户友好的界面设计,为你提供一套完整的开发实践指南。

核心技术架构解析

DID规范与W3C标准

去中心化身份的核心是DID(Decentralized Identifier),这是一种基于W3C标准的新型标识符。与传统的URL或邮箱地址不同,DID不依赖任何中心化机构,具有全球唯一性和自我主权特性。

一个标准的DID结构如下:

复制代码
did:method:identifier

其中:

  • did:固定前缀,表示这是一个去中心化标识符
  • method:指定DID的实现方法,如ethr(以太坊)、key(纯密钥)等
  • identifier:具体的标识符,通常由公钥或其哈希值生成
javascript 复制代码
// DID示例
const ethereumDID = "did:ethr:0x1234567890123456789012345678901234567890";
const keyBasedDID = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK";

DID文档结构

每个DID都对应一个DID文档(DID Document),描述了如何与该身份进行交互:

json 复制代码
{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/ed25519-2020/v1"
  ],
  "id": "did:ethr:0x1234567890123456789012345678901234567890",
  "verificationMethod": [{
    "id": "did:ethr:0x1234567890123456789012345678901234567890#controller",
    "type": "EcdsaSecp256k1RecoveryMethod2020",
    "controller": "did:ethr:0x1234567890123456789012345678901234567890",
    "blockchainAccountId": "eip155:1:0x1234567890123456789012345678901234567890"
  }],
  "authentication": [
    "did:ethr:0x1234567890123456789012345678901234567890#controller"
  ],
  "assertionMethod": [
    "did:ethr:0x1234567890123456789012345678901234567890#controller"
  ],
  "service": [{
    "id": "did:ethr:0x1234567890123456789012345678901234567890#msg",
    "type": "Messaging",
    "serviceEndpoint": "https://example.com/messages"
  }]
}

实现基于DID的身份认证系统

1. 核心身份管理类设计

首先,我们需要构建一个强大的身份管理核心类,处理DID的生成、验证和管理:

javascript 复制代码
import { ethers } from 'ethers';
import { DIDRegistry } from '@ethereum/did-registry';
import { createVerifiableCredential, verifyCredential } from 'did-jwt-vc';

class DecentralizedIdentityManager {
  constructor(provider, registryAddress) {
    this.provider = provider;
    this.registry = new DIDRegistry(provider, registryAddress);
    this.cache = new Map(); // DID文档缓存
  }

  /**
   * 创建新的DID身份
   * @param {string} privateKey - 私钥(可选,不提供则自动生成)
   * @returns {Object} 包含DID、私钥和公钥的身份对象
   */
  async createIdentity(privateKey = null) {
    // 生成或使用提供的私钥
    const wallet = privateKey 
      ? new ethers.Wallet(privateKey, this.provider)
      : ethers.Wallet.createRandom().connect(this.provider);

    const did = `did:ethr:${wallet.address}`;
    
    // 构建DID文档
    const didDocument = {
      '@context': [
        'https://www.w3.org/ns/did/v1',
        'https://w3id.org/security/suites/secp256k1-2019/v1'
      ],
      id: did,
      verificationMethod: [{
        id: `${did}#controller`,
        type: 'EcdsaSecp256k1RecoveryMethod2020',
        controller: did,
        blockchainAccountId: `eip155:1:${wallet.address}`
      }],
      authentication: [`${did}#controller`],
      assertionMethod: [`${did}#controller`]
    };

    // 缓存DID文档
    this.cache.set(did, didDocument);

    return {
      did,
      privateKey: wallet.privateKey,
      publicKey: wallet.publicKey,
      address: wallet.address,
      document: didDocument
    };
  }

  /**
   * 解析DID文档
   * @param {string} did - 要解析的DID
   * @returns {Object} DID文档
   */
  async resolveDID(did) {
    // 先检查缓存
    if (this.cache.has(did)) {
      return this.cache.get(did);
    }

    try {
      // 从区块链获取DID文档
      const address = did.split(':')[2];
      const document = await this.registry.getDocument(address);
      
      this.cache.set(did, document);
      return document;
    } catch (error) {
      console.error('DID解析失败:', error);
      throw new Error(`无法解析DID: ${did}`);
    }
  }

  /**
   * 创建可验证凭证
   * @param {Object} issuer - 颁发者身份
   * @param {Object} subject - 凭证主体
   * @param {Object} credentialData - 凭证数据
   * @returns {string} JWT格式的可验证凭证
   */
  async createVerifiableCredential(issuer, subject, credentialData) {
    const payload = {
      sub: subject.did,
      iss: issuer.did,
      vc: {
        '@context': ['https://www.w3.org/2018/credentials/v1'],
        type: ['VerifiableCredential'],
        credentialSubject: {
          id: subject.did,
          ...credentialData
        }
      }
    };

    // 使用颁发者的私钥签名
    const signer = new ethers.Wallet(issuer.privateKey);
    return await createVerifiableCredential(payload, {
      did: issuer.did,
      signer: signer
    });
  }

  /**
   * 验证可验证凭证
   * @param {string} credential - JWT格式的凭证
   * @returns {Object} 验证结果
   */
  async verifyCredential(credential) {
    try {
      const result = await verifyCredential(credential, {
        resolver: (did) => this.resolveDID(did)
      });
      
      return {
        verified: result.verified,
        payload: result.payload,
        issuer: result.issuer
      };
    } catch (error) {
      console.error('凭证验证失败:', error);
      return { verified: false, error: error.message };
    }
  }
}

2. 多签名算法支持

现代Web3应用需要支持多种签名算法以满足不同的安全需求和性能要求:

javascript 复制代码
import { ec as EC } from 'elliptic';
import nacl from 'tweetnacl';
import { sha256 } from 'js-sha256';

class MultiSignatureManager {
  constructor() {
    this.secp256k1 = new EC('secp256k1');
    this.ed25519 = nacl;
  }

  /**
   * ECDSA-secp256k1签名(以太坊标准)
   * @param {string} message - 要签名的消息
   * @param {string} privateKey - 私钥
   * @returns {Object} 签名结果
   */
  signWithSecp256k1(message, privateKey) {
    const messageHash = sha256(message);
    const keyPair = this.secp256k1.keyFromPrivate(privateKey, 'hex');
    const signature = keyPair.sign(messageHash);
    
    return {
      r: signature.r.toString('hex'),
      s: signature.s.toString('hex'),
      v: signature.recoveryParam + 27, // 以太坊格式
      signature: signature.toDER('hex'),
      algorithm: 'ECDSA-secp256k1'
    };
  }

  /**
   * Ed25519签名(高性能椭圆曲线)
   * @param {string} message - 要签名的消息
   * @param {Uint8Array} secretKey - 私钥
   * @returns {Object} 签名结果
   */
  signWithEd25519(message, secretKey) {
    const messageBytes = new TextEncoder().encode(message);
    const signature = nacl.sign.detached(messageBytes, secretKey);
    
    return {
      signature: Array.from(signature).map(b => b.toString(16).padStart(2, '0')).join(''),
      algorithm: 'Ed25519'
    };
  }

  /**
   * 验证secp256k1签名
   * @param {string} message - 原始消息
   * @param {Object} signature - 签名对象
   * @param {string} publicKey - 公钥
   * @returns {boolean} 验证结果
   */
  verifySecp256k1(message, signature, publicKey) {
    try {
      const messageHash = sha256(message);
      const keyPair = this.secp256k1.keyFromPublic(publicKey, 'hex');
      return keyPair.verify(messageHash, {
        r: signature.r,
        s: signature.s
      });
    } catch (error) {
      console.error('secp256k1签名验证失败:', error);
      return false;
    }
  }

  /**
   * 验证Ed25519签名
   * @param {string} message - 原始消息
   * @param {string} signature - 签名字符串
   * @param {Uint8Array} publicKey - 公钥
   * @returns {boolean} 验证结果
   */
  verifyEd25519(message, signature, publicKey) {
    try {
      const messageBytes = new TextEncoder().encode(message);
      const signatureBytes = new Uint8Array(
        signature.match(/.{2}/g).map(byte => parseInt(byte, 16))
      );
      return nacl.sign.detached.verify(messageBytes, signatureBytes, publicKey);
    } catch (error) {
      console.error('Ed25519签名验证失败:', error);
      return false;
    }
  }

  /**
   * 根据算法类型自动选择验证方法
   * @param {string} message - 原始消息
   * @param {Object} signatureData - 包含算法信息的签名数据
   * @param {string|Uint8Array} publicKey - 公钥
   * @returns {boolean} 验证结果
   */
  verifySignature(message, signatureData, publicKey) {
    switch (signatureData.algorithm) {
      case 'ECDSA-secp256k1':
        return this.verifySecp256k1(message, signatureData, publicKey);
      case 'Ed25519':
        return this.verifyEd25519(message, signatureData.signature, publicKey);
      default:
        throw new Error(`不支持的签名算法: ${signatureData.algorithm}`);
    }
  }
}

EIP-4361标准:以太坊登录实现

EIP-4361(Sign-In with Ethereum)定义了一种标准化的方式,让用户通过以太坊钱包登录Web3应用。这个标准解决了传统OAuth流程在去中心化环境中的局限性。

SIWE消息格式

EIP-4361定义了严格的消息格式,确保安全性和互操作性:

javascript 复制代码
class SIWEManager {
  constructor() {
    this.messageTemplate = `{domain} wants you to sign in with your Ethereum account:
{address}

{statement}

URI: {uri}
Version: {version}
Chain ID: {chainId}
Nonce: {nonce}
Issued At: {issuedAt}
Expiration Time: {expirationTime}
Not Before: {notBefore}
Request ID: {requestId}
Resources:
{resources}`;
  }

  /**
   * 生成SIWE消息
   * @param {Object} params - 消息参数
   * @returns {string} 格式化的SIWE消息
   */
  generateMessage(params) {
    const {
      domain,
      address,
      statement = '',
      uri,
      version = '1',
      chainId,
      nonce,
      issuedAt = new Date().toISOString(),
      expirationTime,
      notBefore,
      requestId,
      resources = []
    } = params;

    // 验证必需字段
    this.validateRequiredFields({ domain, address, uri, chainId, nonce });

    let message = this.messageTemplate
      .replace('{domain}', domain)
      .replace('{address}', address)
      .replace('{statement}', statement)
      .replace('{uri}', uri)
      .replace('{version}', version)
      .replace('{chainId}', chainId)
      .replace('{nonce}', nonce)
      .replace('{issuedAt}', issuedAt);

    // 可选字段处理
    if (expirationTime) {
      message = message.replace('{expirationTime}', expirationTime);
    } else {
      message = message.replace('Expiration Time: {expirationTime}\n', '');
    }

    if (notBefore) {
      message = message.replace('{notBefore}', notBefore);
    } else {
      message = message.replace('Not Before: {notBefore}\n', '');
    }

    if (requestId) {
      message = message.replace('{requestId}', requestId);
    } else {
      message = message.replace('Request ID: {requestId}\n', '');
    }

    // 处理资源列表
    if (resources.length > 0) {
      const resourceList = resources.map(r => `- ${r}`).join('\n');
      message = message.replace('{resources}', resourceList);
    } else {
      message = message.replace('Resources:\n{resources}', '');
    }

    return message.trim();
  }

  /**
   * 验证必需字段
   * @param {Object} fields - 字段对象
   */
  validateRequiredFields(fields) {
    const required = ['domain', 'address', 'uri', 'chainId', 'nonce'];
    for (const field of required) {
      if (!fields[field]) {
        throw new Error(`缺少必需字段: ${field}`);
      }
    }

    // 验证以太坊地址格式
    if (!/^0x[a-fA-F0-9]{40}$/.test(fields.address)) {
      throw new Error('无效的以太坊地址格式');
    }

    // 验证Chain ID
    if (!Number.isInteger(fields.chainId) || fields.chainId <= 0) {
      throw new Error('无效的Chain ID');
    }
  }

  /**
   * 解析SIWE消息
   * @param {string} message - SIWE消息
   * @returns {Object} 解析后的字段
   */
  parseMessage(message) {
    const lines = message.split('\n');
    const result = {};

    // 解析首行域名和地址
    const firstLine = lines[0];
    const domainMatch = firstLine.match(/^(.+) wants you to sign in/);
    result.domain = domainMatch ? domainMatch[1] : '';

    const addressLine = lines[1];
    result.address = addressLine;

    // 解析其他字段
    for (let i = 2; i < lines.length; i++) {
      const line = lines[i].trim();
      if (line.startsWith('URI: ')) {
        result.uri = line.substring(5);
      } else if (line.startsWith('Version: ')) {
        result.version = line.substring(9);
      } else if (line.startsWith('Chain ID: ')) {
        result.chainId = parseInt(line.substring(10));
      } else if (line.startsWith('Nonce: ')) {
        result.nonce = line.substring(7);
      } else if (line.startsWith('Issued At: ')) {
        result.issuedAt = line.substring(11);
      } else if (line.startsWith('Expiration Time: ')) {
        result.expirationTime = line.substring(17);
      } else if (line.startsWith('Not Before: ')) {
        result.notBefore = line.substring(12);
      } else if (line.startsWith('Request ID: ')) {
        result.requestId = line.substring(12);
      } else if (!result.statement && line && !line.includes(':')) {
        result.statement = line;
      }
    }

    return result;
  }

  /**
   * 验证SIWE消息的有效性
   * @param {Object} parsedMessage - 解析后的消息
   * @param {string} signature - 签名
   * @returns {Object} 验证结果
   */
  async validateMessage(parsedMessage, signature) {
    try {
      const now = new Date();
      
      // 检查过期时间
      if (parsedMessage.expirationTime) {
        const expiry = new Date(parsedMessage.expirationTime);
        if (now > expiry) {
          return { valid: false, error: '消息已过期' };
        }
      }

      // 检查生效时间
      if (parsedMessage.notBefore) {
        const notBefore = new Date(parsedMessage.notBefore);
        if (now < notBefore) {
          return { valid: false, error: '消息尚未生效' };
        }
      }

      // 验证签名
      const messageText = this.generateMessage(parsedMessage);
      const recoveredAddress = ethers.utils.verifyMessage(messageText, signature);
      
      if (recoveredAddress.toLowerCase() !== parsedMessage.address.toLowerCase()) {
        return { valid: false, error: '签名验证失败' };
      }

      return { 
        valid: true, 
        address: recoveredAddress,
        message: parsedMessage 
      };
    } catch (error) {
      return { valid: false, error: error.message };
    }
  }

  /**
   * 生成安全的随机nonce
   * @returns {string} 32字节的十六进制nonce
   */
  generateNonce() {
    return ethers.utils.hexlify(ethers.utils.randomBytes(32));
  }
}

钱包连接与多链支持

通用钱包连接器

现代Web3应用需要支持多种钱包,包括MetaMask、WalletConnect、Coinbase Wallet等:

javascript 复制代码
class UniversalWalletConnector {
  constructor() {
    this.connectedWallet = null;
    this.supportedWallets = new Map();
    this.eventListeners = new Map();
    
    this.initializeSupportedWallets();
  }

  /**
   * 初始化支持的钱包列表
   */
  initializeSupportedWallets() {
    this.supportedWallets.set('metamask', {
      name: 'MetaMask',
      icon: '/icons/metamask.svg',
      check: () => window.ethereum && window.ethereum.isMetaMask,
      connect: this.connectMetaMask.bind(this)
    });

    this.supportedWallets.set('coinbase', {
      name: 'Coinbase Wallet',
      icon: '/icons/coinbase.svg',
      check: () => window.ethereum && window.ethereum.isCoinbaseWallet,
      connect: this.connectCoinbaseWallet.bind(this)
    });

    this.supportedWallets.set('walletconnect', {
      name: 'WalletConnect',
      icon: '/icons/walletconnect.svg',
      check: () => true, // WalletConnect通过QR码连接
      connect: this.connectWalletConnect.bind(this)
    });
  }

  /**
   * 获取可用的钱包列表
   * @returns {Array} 可用钱包列表
   */
  getAvailableWallets() {
    return Array.from(this.supportedWallets.entries())
      .filter(([id, wallet]) => wallet.check())
      .map(([id, wallet]) => ({ id, ...wallet }));
  }

  /**
   * 连接MetaMask钱包
   * @returns {Object} 连接结果
   */
  async connectMetaMask() {
    try {
      if (!window.ethereum || !window.ethereum.isMetaMask) {
        throw new Error('MetaMask未安装');
      }

      const accounts = await window.ethereum.request({
        method: 'eth_requestAccounts'
      });

      const chainId = await window.ethereum.request({
        method: 'eth_chainId'
      });

      const walletInfo = {
        type: 'metamask',
        address: accounts[0],
        chainId: parseInt(chainId, 16),
        provider: window.ethereum
      };

      this.connectedWallet = walletInfo;
      this.setupEventListeners();
      
      return { success: true, wallet: walletInfo };
    } catch (error) {
      console.error('MetaMask连接失败:', error);
      return { success: false, error: error.message };
    }
  }

  /**
   * 连接Coinbase Wallet
   * @returns {Object} 连接结果
   */
  async connectCoinbaseWallet() {
    try {
      if (!window.ethereum || !window.ethereum.isCoinbaseWallet) {
        throw new Error('Coinbase Wallet未安装');
      }

      const accounts = await window.ethereum.request({
        method: 'eth_requestAccounts'
      });

      const chainId = await window.ethereum.request({
        method: 'eth_chainId'
      });

      const walletInfo = {
        type: 'coinbase',
        address: accounts[0],
        chainId: parseInt(chainId, 16),
        provider: window.ethereum
      };

      this.connectedWallet = walletInfo;
      this.setupEventListeners();
      
      return { success: true, wallet: walletInfo };
    } catch (error) {
      console.error('Coinbase Wallet连接失败:', error);
      return { success: false, error: error.message };
    }
  }

  /**
   * 连接WalletConnect
   * @returns {Object} 连接结果
   */
  async connectWalletConnect() {
    try {
      const { WalletConnectConnector } = await import('@walletconnect/web3-provider');
      
      const connector = new WalletConnectConnector({
        rpc: {
          1: 'https://mainnet.infura.io/v3/YOUR_INFURA_KEY',
          137: 'https://polygon-rpc.com',
          56: 'https://bsc-dataseed.binance.org'
        },
        qrcode: true,
        pollingInterval: 12000
      });

      await connector.enable();

      const accounts = await connector.request({
        method: 'eth_accounts'
      });

      const chainId = await connector.request({
        method: 'eth_chainId'
      });

      const walletInfo = {
        type: 'walletconnect',
        address: accounts[0],
        chainId: parseInt(chainId, 16),
        provider: connector
      };

      this.connectedWallet = walletInfo;
      this.setupWalletConnectListeners(connector);
      
      return { success: true, wallet: walletInfo };
    } catch (error) {
      console.error('WalletConnect连接失败:', error);
      return { success: false, error: error.message };
    }
  }

  /**
   * 设置事件监听器
   */
  setupEventListeners() {
    if (!this.connectedWallet?.provider) return;

    const provider = this.connectedWallet.provider;

    // 账户变更监听
    provider.on('accountsChanged', (accounts) => {
      if (accounts.length === 0) {
        this.disconnect();
      } else {
        this.connectedWallet.address = accounts[0];
        this.emitEvent('accountChanged', accounts[0]);
      }
    });

    // 网络变更监听
    provider.on('chainChanged', (chainId) => {
      this.connectedWallet.chainId = parseInt(chainId, 16);
      this.emitEvent('chainChanged', parseInt(chainId, 16));
    });

    // 连接断开监听
    provider.on('disconnect', () => {
      this.disconnect();
    });
  }

  /**
   * 设置WalletConnect特定事件监听器
   * @param {Object} connector - WalletConnect连接器
   */
  setupWalletConnectListeners(connector) {
    connector.on('session_update', (error, payload) => {
      if (error) {
        console.error('WalletConnect会话更新错误:', error);
        return;
      }

      const { accounts, chainId } = payload.params[0];
      this.connectedWallet.address = accounts[0];
      this.connectedWallet.chainId = chainId;
      this.emitEvent('accountChanged', accounts[0]);
      this.emitEvent('chainChanged', chainId);
    });

    connector.on('disconnect', (error, payload) => {
      this.disconnect();
    });
  }

  /**
   * 断开钱包连接
   */
  async disconnect() {
    if (this.connectedWallet?.type === 'walletconnect') {
      await this.connectedWallet.provider.disconnect();
    }
    
    this.connectedWallet = null;
    this.emitEvent('disconnected');
  }

  /**
   * 切换网络
   * @param {number} chainId - 目标链ID
   * @returns {boolean} 切换结果
   */
  async switchChain(chainId) {
    if (!this.connectedWallet) {
      throw new Error('未连接钱包');
    }

    try {
      await this.connectedWallet.provider.request({
        method: 'wallet_switchEthereumChain',
        params: [{ chainId: `0x${chainId.toString(16)}` }]
      });
      return true;
    } catch (error) {
      // 如果网络不存在,尝试添加
      if (error.code === 4902) {
        return await this.addChain(chainId);
      }
      throw error;
    }
  }

  /**
   * 添加新网络
   * @param {number} chainId - 链ID
   * @returns {boolean} 添加结果
   */
  async addChain(chainId) {
    const chainConfigs = {
      137: {
        chainId: '0x89',
        chainName: 'Polygon Mainnet',
        nativeCurrency: {
          name: 'MATIC',
          symbol: 'MATIC',
          decimals: 18
        },
        rpcUrls: ['https://polygon-rpc.com'],
        blockExplorerUrls: ['https://polygonscan.com']
      },
      56: {
        chainId: '0x38',
        chainName: 'Binance Smart Chain',
        nativeCurrency: {
          name: 'BNB',
          symbol: 'BNB',
          decimals: 18
        },
        rpcUrls: ['https://bsc-dataseed.binance.org'],
        blockExplorerUrls: ['https://bscscan.com']
      }
    };

    const config = chainConfigs[chainId];
    if (!config) {
      throw new Error(`不支持的链ID: ${chainId}`);
    }

    await this.connectedWallet.provider.request({
      method: 'wallet_addEthereumChain',
      params: [config]
    });

    return true;
  }

  /**
   * 发送事件
   * @param {string} event - 事件名称
   * @param {*} data - 事件数据
   */
  emitEvent(event, data) {
    const listeners = this.eventListeners.get(event) || [];
    listeners.forEach(callback => callback(data));
  }

  /**
   * 添加事件监听器
   * @param {string} event - 事件名称
   * @param {Function} callback - 回调函数
   */
  on(event, callback) {
    if (!this.eventListeners.has(event)) {
      this.eventListeners.set(event, []);
    }
    this.eventListeners.get(event).push(callback);
  }

  /**
   * 移除事件监听器
   * @param {string} event - 事件名称
   * @param {Function} callback - 回调函数
   */
  off(event, callback) {
    const listeners = this.eventListeners.get(event) || [];
    const index = listeners.indexOf(callback);
    if (index > -1) {
      listeners.splice(index, 1);
    }
  }
} 

## 智能合约权限管理系统

### 基于角色的访问控制(RBAC)智能合约

权限管理是Web3身份系统的核心组件。我们需要设计一个灵活且安全的智能合约来管理用户权限:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

/**
 * @title DecentralizedAccessControl
 * @dev 去中心化访问控制合约,支持细粒度权限管理
 */
contract DecentralizedAccessControl is AccessControl, Pausable, ReentrancyGuard {
    // 预定义角色
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    bytes32 public constant MODERATOR_ROLE = keccak256("MODERATOR_ROLE");
    bytes32 public constant USER_ROLE = keccak256("USER_ROLE");
    
    // 自定义权限标识符
    struct Permission {
        bytes32 id;
        string name;
        string description;
        bool active;
    }
    
    // 角色定义
    struct Role {
        bytes32 id;
        string name;
        string description;
        bytes32[] permissions;
        bool active;
    }
    
    // 用户身份信息
    struct UserProfile {
        address userAddress;
        string did;
        bytes32[] roles;
        mapping(bytes32 => bool) permissions;
        bool active;
        uint256 createdAt;
        uint256 updatedAt;
    }
    
    // 存储映射
    mapping(bytes32 => Permission) public permissions;
    mapping(bytes32 => Role) public roles;
    mapping(address => UserProfile) public userProfiles;
    mapping(string => address) public didToAddress;
    
    // 数组用于枚举
    bytes32[] public allPermissions;
    bytes32[] public allRoles;
    address[] public allUsers;
    
    // 事件定义
    event PermissionCreated(bytes32 indexed permissionId, string name);
    event RoleCreated(bytes32 indexed roleId, string name);
    event UserRegistered(address indexed user, string did);
    event RoleAssigned(address indexed user, bytes32 indexed roleId);
    event RoleRevoked(address indexed user, bytes32 indexed roleId);
    event PermissionGranted(address indexed user, bytes32 indexed permissionId);
    event PermissionRevoked(address indexed user, bytes32 indexed permissionId);
    
    constructor() {
        // 设置部署者为默认管理员
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _grantRole(ADMIN_ROLE, msg.sender);
        
        // 创建基础权限
        _createDefaultPermissions();
        _createDefaultRoles();
    }
    
    /**
     * @dev 创建新权限
     * @param _id 权限ID
     * @param _name 权限名称
     * @param _description 权限描述
     */
    function createPermission(
        bytes32 _id,
        string calldata _name,
        string calldata _description
    ) external onlyRole(ADMIN_ROLE) {
        require(!permissions[_id].active, "Permission already exists");
        
        permissions[_id] = Permission({
            id: _id,
            name: _name,
            description: _description,
            active: true
        });
        
        allPermissions.push(_id);
        emit PermissionCreated(_id, _name);
    }
    
    /**
     * @dev 创建新角色
     * @param _id 角色ID
     * @param _name 角色名称
     * @param _description 角色描述
     * @param _permissions 角色包含的权限列表
     */
    function createRole(
        bytes32 _id,
        string calldata _name,
        string calldata _description,
        bytes32[] calldata _permissions
    ) external onlyRole(ADMIN_ROLE) {
        require(!roles[_id].active, "Role already exists");
        
        // 验证所有权限都存在
        for (uint i = 0; i < _permissions.length; i++) {
            require(permissions[_permissions[i]].active, "Invalid permission");
        }
        
        roles[_id] = Role({
            id: _id,
            name: _name,
            description: _description,
            permissions: _permissions,
            active: true
        });
        
        allRoles.push(_id);
        emit RoleCreated(_id, _name);
    }
    
    /**
     * @dev 注册用户身份
     * @param _userAddress 用户地址
     * @param _did 用户DID标识符
     */
    function registerUser(
        address _userAddress,
        string calldata _did
    ) external onlyRole(MODERATOR_ROLE) {
        require(_userAddress != address(0), "Invalid address");
        require(bytes(_did).length > 0, "Invalid DID");
        require(!userProfiles[_userAddress].active, "User already registered");
        require(didToAddress[_did] == address(0), "DID already taken");
        
        UserProfile storage profile = userProfiles[_userAddress];
        profile.userAddress = _userAddress;
        profile.did = _did;
        profile.active = true;
        profile.createdAt = block.timestamp;
        profile.updatedAt = block.timestamp;
        
        didToAddress[_did] = _userAddress;
        allUsers.push(_userAddress);
        
        // 默认分配USER_ROLE
        _assignRole(_userAddress, USER_ROLE);
        
        emit UserRegistered(_userAddress, _did);
    }
    
    /**
     * @dev 为用户分配角色
     * @param _user 用户地址
     * @param _roleId 角色ID
     */
    function assignRole(
        address _user,
        bytes32 _roleId
    ) external onlyRole(MODERATOR_ROLE) {
        _assignRole(_user, _roleId);
    }
    
    /**
     * @dev 内部方法:分配角色
     */
    function _assignRole(address _user, bytes32 _roleId) internal {
        require(userProfiles[_user].active, "User not registered");
        require(roles[_roleId].active, "Role not found");
        
        UserProfile storage profile = userProfiles[_user];
        
        // 检查用户是否已有该角色
        bool hasRole = false;
        for (uint i = 0; i < profile.roles.length; i++) {
            if (profile.roles[i] == _roleId) {
                hasRole = true;
                break;
            }
        }
        
        if (!hasRole) {
            profile.roles.push(_roleId);
            
            // 授予角色包含的所有权限
            Role storage role = roles[_roleId];
            for (uint i = 0; i < role.permissions.length; i++) {
                profile.permissions[role.permissions[i]] = true;
            }
            
            profile.updatedAt = block.timestamp;
            emit RoleAssigned(_user, _roleId);
        }
    }
    
    /**
     * @dev 撤销用户角色
     * @param _user 用户地址
     * @param _roleId 角色ID
     */
    function revokeRole(
        address _user,
        bytes32 _roleId
    ) external onlyRole(MODERATOR_ROLE) {
        require(userProfiles[_user].active, "User not registered");
        
        UserProfile storage profile = userProfiles[_user];
        
        // 查找并移除角色
        for (uint i = 0; i < profile.roles.length; i++) {
            if (profile.roles[i] == _roleId) {
                // 移除角色
                profile.roles[i] = profile.roles[profile.roles.length - 1];
                profile.roles.pop();
                
                // 重新计算权限
                _recalculatePermissions(_user);
                
                profile.updatedAt = block.timestamp;
                emit RoleRevoked(_user, _roleId);
                break;
            }
        }
    }
    
    /**
     * @dev 直接授予用户权限
     * @param _user 用户地址
     * @param _permissionId 权限ID
     */
    function grantPermission(
        address _user,
        bytes32 _permissionId
    ) external onlyRole(ADMIN_ROLE) {
        require(userProfiles[_user].active, "User not registered");
        require(permissions[_permissionId].active, "Permission not found");
        
        UserProfile storage profile = userProfiles[_user];
        profile.permissions[_permissionId] = true;
        profile.updatedAt = block.timestamp;
        
        emit PermissionGranted(_user, _permissionId);
    }
    
    /**
     * @dev 撤销用户权限
     * @param _user 用户地址
     * @param _permissionId 权限ID
     */
    function revokePermission(
        address _user,
        bytes32 _permissionId
    ) external onlyRole(ADMIN_ROLE) {
        require(userProfiles[_user].active, "User not registered");
        
        UserProfile storage profile = userProfiles[_user];
        profile.permissions[_permissionId] = false;
        profile.updatedAt = block.timestamp;
        
        emit PermissionRevoked(_user, _permissionId);
    }
    
    /**
     * @dev 检查用户是否有特定权限
     * @param _user 用户地址
     * @param _permissionId 权限ID
     * @return 是否有权限
     */
    function hasPermission(
        address _user,
        bytes32 _permissionId
    ) external view returns (bool) {
        if (!userProfiles[_user].active) return false;
        return userProfiles[_user].permissions[_permissionId];
    }
    
    /**
     * @dev 获取用户的所有角色
     * @param _user 用户地址
     * @return 角色ID数组
     */
    function getUserRoles(address _user) external view returns (bytes32[] memory) {
        require(userProfiles[_user].active, "User not registered");
        return userProfiles[_user].roles;
    }
    
    /**
     * @dev 获取角色的所有权限
     * @param _roleId 角色ID
     * @return 权限ID数组
     */
    function getRolePermissions(bytes32 _roleId) external view returns (bytes32[] memory) {
        require(roles[_roleId].active, "Role not found");
        return roles[_roleId].permissions;
    }
    
    /**
     * @dev 重新计算用户权限
     * @param _user 用户地址
     */
    function _recalculatePermissions(address _user) internal {
        UserProfile storage profile = userProfiles[_user];
        
        // 清除所有权限
        for (uint i = 0; i < allPermissions.length; i++) {
            profile.permissions[allPermissions[i]] = false;
        }
        
        // 重新授予基于角色的权限
        for (uint i = 0; i < profile.roles.length; i++) {
            Role storage role = roles[profile.roles[i]];
            for (uint j = 0; j < role.permissions.length; j++) {
                profile.permissions[role.permissions[j]] = true;
            }
        }
    }
    
    /**
     * @dev 创建默认权限
     */
    function _createDefaultPermissions() internal {
        bytes32[] memory defaultPerms = new bytes32[](6);
        defaultPerms[0] = keccak256("READ_PROFILE");
        defaultPerms[1] = keccak256("WRITE_PROFILE");
        defaultPerms[2] = keccak256("CREATE_CONTENT");
        defaultPerms[3] = keccak256("MODERATE_CONTENT");
        defaultPerms[4] = keccak256("MANAGE_USERS");
        defaultPerms[5] = keccak256("SYSTEM_ADMIN");
        
        string[] memory names = new string[](6);
        names[0] = "Read Profile";
        names[1] = "Write Profile";
        names[2] = "Create Content";
        names[3] = "Moderate Content";
        names[4] = "Manage Users";
        names[5] = "System Admin";
        
        for (uint i = 0; i < defaultPerms.length; i++) {
            permissions[defaultPerms[i]] = Permission({
                id: defaultPerms[i],
                name: names[i],
                description: "",
                active: true
            });
            allPermissions.push(defaultPerms[i]);
        }
    }
    
    /**
     * @dev 创建默认角色
     */
    function _createDefaultRoles() internal {
        // USER角色权限
        bytes32[] memory userPermissions = new bytes32[](2);
        userPermissions[0] = keccak256("READ_PROFILE");
        userPermissions[1] = keccak256("WRITE_PROFILE");
        
        roles[USER_ROLE] = Role({
            id: USER_ROLE,
            name: "User",
            description: "Basic user role",
            permissions: userPermissions,
            active: true
        });
        allRoles.push(USER_ROLE);
        
        // MODERATOR角色权限
        bytes32[] memory modPermissions = new bytes32[](4);
        modPermissions[0] = keccak256("READ_PROFILE");
        modPermissions[1] = keccak256("WRITE_PROFILE");
        modPermissions[2] = keccak256("CREATE_CONTENT");
        modPermissions[3] = keccak256("MODERATE_CONTENT");
        
        roles[MODERATOR_ROLE] = Role({
            id: MODERATOR_ROLE,
            name: "Moderator",
            description: "Content moderator role",
            permissions: modPermissions,
            active: true
        });
        allRoles.push(MODERATOR_ROLE);
        
        // ADMIN角色权限
        bytes32[] memory adminPermissions = new bytes32[](6);
        adminPermissions[0] = keccak256("READ_PROFILE");
        adminPermissions[1] = keccak256("WRITE_PROFILE");
        adminPermissions[2] = keccak256("CREATE_CONTENT");
        adminPermissions[3] = keccak256("MODERATE_CONTENT");
        adminPermissions[4] = keccak256("MANAGE_USERS");
        adminPermissions[5] = keccak256("SYSTEM_ADMIN");
        
        roles[ADMIN_ROLE] = Role({
            id: ADMIN_ROLE,
            name: "Admin",
            description: "System administrator role",
            permissions: adminPermissions,
            active: true
        });
        allRoles.push(ADMIN_ROLE);
    }
    
    /**
     * @dev 暂停合约(仅管理员)
     */
    function pause() external onlyRole(ADMIN_ROLE) {
        _pause();
    }
    
    /**
     * @dev 恢复合约(仅管理员)
     */
    function unpause() external onlyRole(ADMIN_ROLE) {
        _unpause();
    }
}

JavaScript智能合约交互层

javascript 复制代码
import { ethers } from 'ethers';

class AccessControlManager {
  constructor(contractAddress, provider, signer) {
    this.contractAddress = contractAddress;
    this.provider = provider;
    this.signer = signer;
    
    // 加载合约ABI(这里简化展示)
    this.contractABI = [
      // ... 完整的合约ABI
    ];
    
    this.contract = new ethers.Contract(
      contractAddress,
      this.contractABI,
      signer
    );
    
    this.cache = new Map();
  }

  /**
   * 注册新用户
   * @param {string} userAddress - 用户地址
   * @param {string} did - 用户DID
   * @returns {Object} 交易结果
   */
  async registerUser(userAddress, did) {
    try {
      const tx = await this.contract.registerUser(userAddress, did);
      const receipt = await tx.wait();
      
      return {
        success: true,
        txHash: tx.hash,
        gasUsed: receipt.gasUsed.toString(),
        blockNumber: receipt.blockNumber
      };
    } catch (error) {
      console.error('用户注册失败:', error);
      return {
        success: false,
        error: this.parseError(error)
      };
    }
  }

  /**
   * 为用户分配角色
   * @param {string} userAddress - 用户地址
   * @param {string} roleId - 角色ID
   * @returns {Object} 交易结果
   */
  async assignRole(userAddress, roleId) {
    try {
      const roleBytes32 = ethers.utils.formatBytes32String(roleId);
      const tx = await this.contract.assignRole(userAddress, roleBytes32);
      const receipt = await tx.wait();
      
      // 清除相关缓存
      this.cache.delete(`permissions_${userAddress}`);
      this.cache.delete(`roles_${userAddress}`);
      
      return {
        success: true,
        txHash: tx.hash,
        gasUsed: receipt.gasUsed.toString()
      };
    } catch (error) {
      console.error('角色分配失败:', error);
      return {
        success: false,
        error: this.parseError(error)
      };
    }
  }

  /**
   * 检查用户权限
   * @param {string} userAddress - 用户地址
   * @param {string} permissionId - 权限ID
   * @returns {boolean} 是否有权限
   */
  async hasPermission(userAddress, permissionId) {
    const cacheKey = `permission_${userAddress}_${permissionId}`;
    
    // 检查缓存
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey);
    }

    try {
      const permissionBytes32 = ethers.utils.formatBytes32String(permissionId);
      const hasPermission = await this.contract.hasPermission(
        userAddress, 
        permissionBytes32
      );
      
      // 缓存结果(5分钟过期)
      this.cache.set(cacheKey, hasPermission);
      setTimeout(() => this.cache.delete(cacheKey), 5 * 60 * 1000);
      
      return hasPermission;
    } catch (error) {
      console.error('权限检查失败:', error);
      return false;
    }
  }

  /**
   * 获取用户所有角色
   * @param {string} userAddress - 用户地址
   * @returns {Array} 角色列表
   */
  async getUserRoles(userAddress) {
    const cacheKey = `roles_${userAddress}`;
    
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey);
    }

    try {
      const roleBytes32Array = await this.contract.getUserRoles(userAddress);
      const roles = roleBytes32Array.map(role => 
        ethers.utils.parseBytes32String(role)
      );
      
      this.cache.set(cacheKey, roles);
      setTimeout(() => this.cache.delete(cacheKey), 5 * 60 * 1000);
      
      return roles;
    } catch (error) {
      console.error('获取用户角色失败:', error);
      return [];
    }
  }

  /**
   * 创建新角色
   * @param {string} roleId - 角色ID
   * @param {string} name - 角色名称
   * @param {string} description - 角色描述
   * @param {Array} permissions - 权限列表
   * @returns {Object} 交易结果
   */
  async createRole(roleId, name, description, permissions) {
    try {
      const roleBytes32 = ethers.utils.formatBytes32String(roleId);
      const permissionBytes32Array = permissions.map(p => 
        ethers.utils.formatBytes32String(p)
      );
      
      const tx = await this.contract.createRole(
        roleBytes32,
        name,
        description,
        permissionBytes32Array
      );
      const receipt = await tx.wait();
      
      return {
        success: true,
        txHash: tx.hash,
        gasUsed: receipt.gasUsed.toString()
      };
    } catch (error) {
      console.error('角色创建失败:', error);
      return {
        success: false,
        error: this.parseError(error)
      };
    }
  }

  /**
   * 监听权限变更事件
   * @param {Function} callback - 回调函数
   */
  watchPermissionChanges(callback) {
    // 监听角色分配事件
    this.contract.on('RoleAssigned', (user, roleId, event) => {
      callback({
        type: 'RoleAssigned',
        user,
        roleId: ethers.utils.parseBytes32String(roleId),
        blockNumber: event.blockNumber,
        txHash: event.transactionHash
      });
    });

    // 监听角色撤销事件
    this.contract.on('RoleRevoked', (user, roleId, event) => {
      callback({
        type: 'RoleRevoked',
        user,
        roleId: ethers.utils.parseBytes32String(roleId),
        blockNumber: event.blockNumber,
        txHash: event.transactionHash
      });
    });

    // 监听权限直接授予事件
    this.contract.on('PermissionGranted', (user, permissionId, event) => {
      callback({
        type: 'PermissionGranted',
        user,
        permissionId: ethers.utils.parseBytes32String(permissionId),
        blockNumber: event.blockNumber,
        txHash: event.transactionHash
      });
    });
  }

  /**
   * 批量权限检查
   * @param {string} userAddress - 用户地址
   * @param {Array} permissionIds - 权限ID列表
   * @returns {Object} 权限检查结果
   */
  async batchCheckPermissions(userAddress, permissionIds) {
    const results = {};
    
    // 使用Promise.all并行检查所有权限
    const checks = permissionIds.map(async (permissionId) => {
      const hasPermission = await this.hasPermission(userAddress, permissionId);
      return { permissionId, hasPermission };
    });
    
    const permissionResults = await Promise.all(checks);
    
    permissionResults.forEach(({ permissionId, hasPermission }) => {
      results[permissionId] = hasPermission;
    });
    
    return results;
  }

  /**
   * 解析合约错误
   * @param {Error} error - 错误对象
   * @returns {string} 用户友好的错误信息
   */
  parseError(error) {
    if (error.code === 'UNPREDICTABLE_GAS_LIMIT') {
      return '交易可能会失败,请检查参数';
    }
    
    if (error.code === 'INSUFFICIENT_FUNDS') {
      return '账户余额不足';
    }
    
    if (error.message.includes('User not registered')) {
      return '用户未注册';
    }
    
    if (error.message.includes('Role not found')) {
      return '角色不存在';
    }
    
    return error.message || '未知错误';
  }

  /**
   * 获取Gas费用估算
   * @param {string} method - 方法名
   * @param {Array} args - 参数
   * @returns {Object} Gas估算结果
   */
  async estimateGas(method, args) {
    try {
      const gasEstimate = await this.contract.estimateGas[method](...args);
      const gasPrice = await this.provider.getGasPrice();
      
      return {
        gasLimit: gasEstimate.toString(),
        gasPrice: gasPrice.toString(),
        estimatedCost: gasEstimate.mul(gasPrice).toString()
      };
    } catch (error) {
      console.error('Gas估算失败:', error);
      return null;
    }
  }
} 

用户友好的密钥管理界面

现代化React组件设计

在Web3应用中,密钥管理的用户体验往往是成败的关键。用户需要简单直观的界面来管理他们的数字身份,同时保持最高级别的安全性:

jsx 复制代码
import React, { useState, useEffect, useCallback } from 'react';
import { ethers } from 'ethers';
import { QRCodeSVG } from 'qrcode.react';
import { FiCopy, FiEye, FiEyeOff, FiShield, FiUser, FiKey } from 'react-icons/fi';

const IdentityManager = () => {
  const [currentIdentity, setCurrentIdentity] = useState(null);
  const [walletConnector, setWalletConnector] = useState(null);
  const [identityManager, setIdentityManager] = useState(null);
  const [siweManager, setSiweManager] = useState(null);
  const [showPrivateKey, setShowPrivateKey] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState('');
  const [success, setSuccess] = useState('');

  // 初始化组件
  useEffect(() => {
    initializeServices();
  }, []);

  const initializeServices = async () => {
    try {
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const signer = provider.getSigner();
      
      // 初始化各种服务
      const wallet = new UniversalWalletConnector();
      const identity = new DecentralizedIdentityManager(provider, 'CONTRACT_ADDRESS');
      const siwe = new SIWEManager();
      
      setWalletConnector(wallet);
      setIdentityManager(identity);
      setSiweManager(siwe);
    } catch (error) {
      setError('服务初始化失败: ' + error.message);
    }
  };

  const handleCreateIdentity = async () => {
    setIsLoading(true);
    setError('');
    
    try {
      const newIdentity = await identityManager.createIdentity();
      setCurrentIdentity(newIdentity);
      setSuccess('身份创建成功!');
      
      // 自动保存到本地存储(加密)
      await saveIdentitySecurely(newIdentity);
    } catch (error) {
      setError('身份创建失败: ' + error.message);
    } finally {
      setIsLoading(false);
    }
  };

  const handleWalletConnect = async (walletType) => {
    setIsLoading(true);
    setError('');
    
    try {
      const result = await walletConnector.connectMetaMask();
      if (result.success) {
        setSuccess(`${walletType} 连接成功!`);
        
        // 自动注册身份
        const did = `did:ethr:${result.wallet.address}`;
        const identity = {
          did,
          address: result.wallet.address,
          chainId: result.wallet.chainId
        };
        setCurrentIdentity(identity);
      } else {
        setError(result.error);
      }
    } catch (error) {
      setError('钱包连接失败: ' + error.message);
    } finally {
      setIsLoading(false);
    }
  };

  const handleSignMessage = async () => {
    if (!currentIdentity || !siweManager) return;
    
    setIsLoading(true);
    try {
      const message = siweManager.generateMessage({
        domain: window.location.host,
        address: currentIdentity.address,
        uri: window.location.origin,
        chainId: currentIdentity.chainId,
        nonce: siweManager.generateNonce(),
        statement: '登录到去中心化身份管理系统'
      });

      const signature = await window.ethereum.request({
        method: 'personal_sign',
        params: [message, currentIdentity.address]
      });

      const verification = await siweManager.validateMessage(
        siweManager.parseMessage(message), 
        signature
      );

      if (verification.valid) {
        setSuccess('消息签名验证成功!');
      } else {
        setError('签名验证失败: ' + verification.error);
      }
    } catch (error) {
      setError('签名过程失败: ' + error.message);
    } finally {
      setIsLoading(false);
    }
  };

  const copyToClipboard = (text) => {
    navigator.clipboard.writeText(text);
    setSuccess('已复制到剪贴板');
  };

  const saveIdentitySecurely = async (identity) => {
    // 这里应该使用更安全的加密存储方案
    const encryptedData = btoa(JSON.stringify(identity));
    localStorage.setItem('encrypted_identity', encryptedData);
  };

  return (
    <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 p-6">
      <div className="max-w-4xl mx-auto">
        {/* 头部 */}
        <div className="text-center mb-8">
          <h1 className="text-4xl font-bold text-gray-900 mb-2">
            去中心化身份管理
          </h1>
          <p className="text-gray-600">
            安全、可控、跨平台的Web3身份解决方案
          </p>
        </div>

        {/* 错误和成功提示 */}
        {error && (
          <div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg mb-6">
            {error}
          </div>
        )}
        {success && (
          <div className="bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-lg mb-6">
            {success}
          </div>
        )}

        <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
          {/* 左侧 - 身份信息 */}
          <div className="bg-white rounded-xl shadow-lg p-6">
            <div className="flex items-center mb-6">
              <FiUser className="text-2xl text-blue-500 mr-3" />
              <h2 className="text-2xl font-semibold">身份信息</h2>
            </div>

            {currentIdentity ? (
              <div className="space-y-4">
                {/* DID显示 */}
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-2">
                    去中心化标识符 (DID)
                  </label>
                  <div className="flex items-center space-x-2">
                    <div className="flex-1 p-3 bg-gray-50 rounded-lg font-mono text-sm">
                      {currentIdentity.did}
                    </div>
                    <button
                      onClick={() => copyToClipboard(currentIdentity.did)}
                      className="p-2 text-gray-500 hover:text-blue-500 transition-colors"
                    >
                      <FiCopy />
                    </button>
                  </div>
                </div>

                {/* 地址显示 */}
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-2">
                    钱包地址
                  </label>
                  <div className="flex items-center space-x-2">
                    <div className="flex-1 p-3 bg-gray-50 rounded-lg font-mono text-sm">
                      {currentIdentity.address}
                    </div>
                    <button
                      onClick={() => copyToClipboard(currentIdentity.address)}
                      className="p-2 text-gray-500 hover:text-blue-500 transition-colors"
                    >
                      <FiCopy />
                    </button>
                  </div>
                </div>

                {/* 私钥显示(如果有) */}
                {currentIdentity.privateKey && (
                  <div>
                    <label className="block text-sm font-medium text-gray-700 mb-2">
                      私钥 (请妥善保管)
                    </label>
                    <div className="flex items-center space-x-2">
                      <div className="flex-1 p-3 bg-yellow-50 border border-yellow-200 rounded-lg font-mono text-sm">
                        {showPrivateKey 
                          ? currentIdentity.privateKey 
                          : '•'.repeat(64)
                        }
                      </div>
                      <button
                        onClick={() => setShowPrivateKey(!showPrivateKey)}
                        className="p-2 text-gray-500 hover:text-blue-500 transition-colors"
                      >
                        {showPrivateKey ? <FiEyeOff /> : <FiEye />}
                      </button>
                      <button
                        onClick={() => copyToClipboard(currentIdentity.privateKey)}
                        className="p-2 text-gray-500 hover:text-blue-500 transition-colors"
                      >
                        <FiCopy />
                      </button>
                    </div>
                    <p className="text-xs text-yellow-600 mt-1">
                      ⚠️ 请将私钥保存在安全的地方,丢失后无法恢复
                    </p>
                  </div>
                )}

                {/* QR码 */}
                <div className="text-center">
                  <label className="block text-sm font-medium text-gray-700 mb-2">
                    DID二维码
                  </label>
                  <div className="inline-block p-4 bg-white border rounded-lg">
                    <QRCodeSVG value={currentIdentity.did} size={120} />
                  </div>
                </div>

                {/* 操作按钮 */}
                <div className="flex space-x-3 pt-4">
                  <button
                    onClick={handleSignMessage}
                    disabled={isLoading}
                    className="flex-1 bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 disabled:opacity-50 transition-colors"
                  >
                    {isLoading ? '签名中...' : '测试签名'}
                  </button>
                  <button
                    onClick={() => setCurrentIdentity(null)}
                    className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
                  >
                    清除身份
                  </button>
                </div>
              </div>
            ) : (
              <div className="text-center py-8">
                <FiUser className="text-6xl text-gray-300 mx-auto mb-4" />
                <p className="text-gray-500 mb-6">暂无身份信息</p>
                <button
                  onClick={handleCreateIdentity}
                  disabled={isLoading}
                  className="bg-blue-500 text-white py-2 px-6 rounded-lg hover:bg-blue-600 disabled:opacity-50 transition-colors"
                >
                  {isLoading ? '创建中...' : '创建新身份'}
                </button>
              </div>
            )}
          </div>

          {/* 右侧 - 钱包连接 */}
          <div className="bg-white rounded-xl shadow-lg p-6">
            <div className="flex items-center mb-6">
              <FiKey className="text-2xl text-green-500 mr-3" />
              <h2 className="text-2xl font-semibold">钱包连接</h2>
            </div>

            <div className="space-y-4">
              {/* MetaMask */}
              <button
                onClick={() => handleWalletConnect('MetaMask')}
                disabled={isLoading}
                className="w-full flex items-center justify-between p-4 border border-gray-200 rounded-lg hover:border-orange-300 hover:bg-orange-50 transition-colors disabled:opacity-50"
              >
                <div className="flex items-center">
                  <img 
                    src="/icons/metamask.svg" 
                    alt="MetaMask" 
                    className="w-8 h-8 mr-3"
                  />
                  <div className="text-left">
                    <div className="font-medium">MetaMask</div>
                    <div className="text-sm text-gray-500">最流行的以太坊钱包</div>
                  </div>
                </div>
                <div className="text-sm text-gray-400">→</div>
              </button>

              {/* Coinbase Wallet */}
              <button
                onClick={() => handleWalletConnect('Coinbase')}
                disabled={isLoading}
                className="w-full flex items-center justify-between p-4 border border-gray-200 rounded-lg hover:border-blue-300 hover:bg-blue-50 transition-colors disabled:opacity-50"
              >
                <div className="flex items-center">
                  <img 
                    src="/icons/coinbase.svg" 
                    alt="Coinbase" 
                    className="w-8 h-8 mr-3"
                  />
                  <div className="text-left">
                    <div className="font-medium">Coinbase Wallet</div>
                    <div className="text-sm text-gray-500">安全可靠的多链钱包</div>
                  </div>
                </div>
                <div className="text-sm text-gray-400">→</div>
              </button>

              {/* WalletConnect */}
              <button
                onClick={() => handleWalletConnect('WalletConnect')}
                disabled={isLoading}
                className="w-full flex items-center justify-between p-4 border border-gray-200 rounded-lg hover:border-purple-300 hover:bg-purple-50 transition-colors disabled:opacity-50"
              >
                <div className="flex items-center">
                  <img 
                    src="/icons/walletconnect.svg" 
                    alt="WalletConnect" 
                    className="w-8 h-8 mr-3"
                  />
                  <div className="text-left">
                    <div className="font-medium">WalletConnect</div>
                    <div className="text-sm text-gray-500">连接移动端钱包</div>
                  </div>
                </div>
                <div className="text-sm text-gray-400">→</div>
              </button>
            </div>

            {/* 安全提示 */}
            <div className="mt-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
              <div className="flex items-start">
                <FiShield className="text-blue-500 mt-0.5 mr-2" />
                <div className="text-sm text-blue-700">
                  <div className="font-medium mb-1">安全提示</div>
                  <ul className="space-y-1">
                    <li>• 请确保钱包来源可信</li>
                    <li>• 永远不要分享你的私钥</li>
                    <li>• 定期备份你的助记词</li>
                  </ul>
                </div>
              </div>
            </div>
          </div>
        </div>

        {/* 底部功能区 */}
        <div className="mt-8 grid grid-cols-1 md:grid-cols-3 gap-6">
          {/* 身份验证历史 */}
          <div className="bg-white rounded-xl shadow-lg p-6">
            <h3 className="text-lg font-semibold mb-4">验证历史</h3>
            <div className="space-y-3">
              <div className="flex justify-between items-center text-sm">
                <span>登录验证</span>
                <span className="text-green-500">成功</span>
              </div>
              <div className="flex justify-between items-center text-sm">
                <span>权限检查</span>
                <span className="text-green-500">通过</span>
              </div>
              <div className="flex justify-between items-center text-sm">
                <span>签名验证</span>
                <span className="text-yellow-500">待处理</span>
              </div>
            </div>
          </div>

          {/* 网络状态 */}
          <div className="bg-white rounded-xl shadow-lg p-6">
            <h3 className="text-lg font-semibold mb-4">网络状态</h3>
            <div className="space-y-3">
              <div className="flex justify-between items-center text-sm">
                <span>以太坊主网</span>
                <span className="text-green-500">● 已连接</span>
              </div>
              <div className="flex justify-between items-center text-sm">
                <span>Polygon</span>
                <span className="text-gray-400">○ 未连接</span>
              </div>
              <div className="flex justify-between items-center text-sm">
                <span>BSC</span>
                <span className="text-gray-400">○ 未连接</span>
              </div>
            </div>
          </div>

          {/* 快捷操作 */}
          <div className="bg-white rounded-xl shadow-lg p-6">
            <h3 className="text-lg font-semibold mb-4">快捷操作</h3>
            <div className="space-y-2">
              <button className="w-full text-left text-sm py-2 px-3 rounded hover:bg-gray-50">
                导出身份信息
              </button>
              <button className="w-full text-left text-sm py-2 px-3 rounded hover:bg-gray-50">
                导入已有身份
              </button>
              <button className="w-full text-left text-sm py-2 px-3 rounded hover:bg-gray-50">
                查看权限详情
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default IdentityManager;

完整应用实例

集成所有组件的主应用

javascript 复制代码
import React, { useState, useEffect } from 'react';
import { ethers } from 'ethers';

// 导入我们之前创建的所有组件
import IdentityManager from './components/IdentityManager';
import { DecentralizedIdentityManager } from './services/DecentralizedIdentityManager';
import { UniversalWalletConnector } from './services/UniversalWalletConnector';
import { SIWEManager } from './services/SIWEManager';
import { AccessControlManager } from './services/AccessControlManager';
import { MultiSignatureManager } from './services/MultiSignatureManager';

class Web3IdentityApp {
  constructor() {
    this.provider = null;
    this.signer = null;
    this.services = {};
    this.isInitialized = false;
  }

  async initialize() {
    try {
      // 检查MetaMask或其他Web3 provider
      if (typeof window.ethereum === 'undefined') {
        throw new Error('请安装MetaMask或其他Web3钱包');
      }

      this.provider = new ethers.providers.Web3Provider(window.ethereum);
      this.signer = this.provider.getSigner();

      // 初始化所有服务
      await this.initializeServices();

      this.isInitialized = true;
      console.log('Web3身份应用初始化完成');
    } catch (error) {
      console.error('应用初始化失败:', error);
      throw error;
    }
  }

  async initializeServices() {
    // 初始化身份管理器
    this.services.identityManager = new DecentralizedIdentityManager(
      this.provider,
      process.env.REACT_APP_IDENTITY_CONTRACT_ADDRESS
    );

    // 初始化钱包连接器
    this.services.walletConnector = new UniversalWalletConnector();

    // 初始化SIWE管理器
    this.services.siweManager = new SIWEManager();

    // 初始化访问控制管理器
    this.services.accessControlManager = new AccessControlManager(
      process.env.REACT_APP_ACCESS_CONTROL_CONTRACT_ADDRESS,
      this.provider,
      this.signer
    );

    // 初始化多签名管理器
    this.services.multiSignatureManager = new MultiSignatureManager();

    // 设置事件监听
    this.setupEventListeners();
  }

  setupEventListeners() {
    // 监听钱包连接状态变化
    this.services.walletConnector.on('accountChanged', (newAccount) => {
      console.log('账户已切换:', newAccount);
      this.handleAccountChange(newAccount);
    });

    this.services.walletConnector.on('chainChanged', (newChainId) => {
      console.log('网络已切换:', newChainId);
      this.handleChainChange(newChainId);
    });

    this.services.walletConnector.on('disconnected', () => {
      console.log('钱包已断开连接');
      this.handleDisconnection();
    });

    // 监听权限变更
    this.services.accessControlManager.watchPermissionChanges((event) => {
      console.log('权限变更事件:', event);
      this.handlePermissionChange(event);
    });
  }

  async handleAccountChange(newAccount) {
    // 当用户切换账户时,需要重新验证身份
    try {
      const userRoles = await this.services.accessControlManager.getUserRoles(newAccount);
      console.log('新账户角色:', userRoles);
      
      // 触发UI更新
      this.emit('accountChanged', { account: newAccount, roles: userRoles });
    } catch (error) {
      console.error('处理账户切换失败:', error);
    }
  }

  async handleChainChange(newChainId) {
    // 检查新网络是否受支持
    const supportedChains = [1, 137, 56]; // 以太坊主网、Polygon、BSC
    
    if (!supportedChains.includes(newChainId)) {
      console.warn('不支持的网络:', newChainId);
      // 可以提示用户切换到支持的网络
      return;
    }

    // 重新初始化相关服务
    await this.reinitializeForNewChain(newChainId);
  }

  async reinitializeForNewChain(chainId) {
    try {
      // 根据新的链ID更新合约地址
      const contractAddresses = this.getContractAddresses(chainId);
      
      // 重新初始化访问控制管理器
      this.services.accessControlManager = new AccessControlManager(
        contractAddresses.accessControl,
        this.provider,
        this.signer
      );

      console.log(`已切换到链 ${chainId},服务重新初始化完成`);
    } catch (error) {
      console.error('网络切换后重新初始化失败:', error);
    }
  }

  getContractAddresses(chainId) {
    const addresses = {
      1: { // 以太坊主网
        accessControl: process.env.REACT_APP_ETH_ACCESS_CONTROL_ADDRESS,
        identity: process.env.REACT_APP_ETH_IDENTITY_ADDRESS
      },
      137: { // Polygon
        accessControl: process.env.REACT_APP_POLYGON_ACCESS_CONTROL_ADDRESS,
        identity: process.env.REACT_APP_POLYGON_IDENTITY_ADDRESS
      },
      56: { // BSC
        accessControl: process.env.REACT_APP_BSC_ACCESS_CONTROL_ADDRESS,
        identity: process.env.REACT_APP_BSC_IDENTITY_ADDRESS
      }
    };

    return addresses[chainId] || addresses[1]; // 默认使用以太坊主网
  }

  async handleDisconnection() {
    // 清除用户状态
    this.emit('disconnected');
  }

  async handlePermissionChange(event) {
    // 权限变更时更新UI状态
    this.emit('permissionChanged', event);
  }

  // 提供给外部调用的统一接口
  async createIdentity() {
    if (!this.isInitialized) {
      await this.initialize();
    }
    return await this.services.identityManager.createIdentity();
  }

  async connectWallet(walletType = 'metamask') {
    if (!this.isInitialized) {
      await this.initialize();
    }
    return await this.services.walletConnector.connectMetaMask();
  }

  async signInWithEthereum(domain, statement) {
    if (!this.services.walletConnector.connectedWallet) {
      throw new Error('请先连接钱包');
    }

    const wallet = this.services.walletConnector.connectedWallet;
    const message = this.services.siweManager.generateMessage({
      domain,
      address: wallet.address,
      uri: window.location.origin,
      chainId: wallet.chainId,
      nonce: this.services.siweManager.generateNonce(),
      statement
    });

    const signature = await wallet.provider.request({
      method: 'personal_sign',
      params: [message, wallet.address]
    });

    return await this.services.siweManager.validateMessage(
      this.services.siweManager.parseMessage(message),
      signature
    );
  }

  async checkPermission(permissionId) {
    if (!this.services.walletConnector.connectedWallet) {
      return false;
    }

    const address = this.services.walletConnector.connectedWallet.address;
    return await this.services.accessControlManager.hasPermission(address, permissionId);
  }

  // 事件系统
  constructor() {
    // ... 其他初始化代码
    this.eventListeners = new Map();
  }

  on(event, callback) {
    if (!this.eventListeners.has(event)) {
      this.eventListeners.set(event, []);
    }
    this.eventListeners.get(event).push(callback);
  }

  emit(event, data) {
    const listeners = this.eventListeners.get(event) || [];
    listeners.forEach(callback => callback(data));
  }
}

// 使用示例
const app = new Web3IdentityApp();

// React Hook封装
const useWeb3Identity = () => {
  const [isConnected, setIsConnected] = useState(false);
  const [currentAccount, setCurrentAccount] = useState(null);
  const [userPermissions, setUserPermissions] = useState({});
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    // 监听应用事件
    app.on('accountChanged', ({ account, roles }) => {
      setCurrentAccount(account);
      setIsConnected(true);
    });

    app.on('disconnected', () => {
      setIsConnected(false);
      setCurrentAccount(null);
      setUserPermissions({});
    });

    app.on('permissionChanged', (event) => {
      // 重新获取用户权限
      refreshUserPermissions();
    });

    return () => {
      // 清理事件监听器
    };
  }, []);

  const connectWallet = async () => {
    setLoading(true);
    try {
      const result = await app.connectWallet();
      if (result.success) {
        setIsConnected(true);
        setCurrentAccount(result.wallet.address);
        await refreshUserPermissions();
      }
      return result;
    } finally {
      setLoading(false);
    }
  };

  const signIn = async (statement = '登录到去中心化应用') => {
    setLoading(true);
    try {
      return await app.signInWithEthereum(window.location.host, statement);
    } finally {
      setLoading(false);
    }
  };

  const refreshUserPermissions = async () => {
    if (!currentAccount) return;

    const permissions = ['READ_PROFILE', 'WRITE_PROFILE', 'CREATE_CONTENT', 'MODERATE_CONTENT'];
    const results = await app.services.accessControlManager.batchCheckPermissions(
      currentAccount,
      permissions
    );
    setUserPermissions(results);
  };

  const hasPermission = (permissionId) => {
    return userPermissions[permissionId] || false;
  };

  return {
    isConnected,
    currentAccount,
    userPermissions,
    loading,
    connectWallet,
    signIn,
    hasPermission,
    refreshUserPermissions
  };
};

export { Web3IdentityApp, useWeb3Identity };

性能优化策略

智能合约Gas优化

在以太坊等区块链网络上,Gas费用是一个重要考虑因素。以下是一些关键的优化策略:

solidity 复制代码
// 优化后的权限检查函数
contract OptimizedAccessControl {
    // 使用位操作优化权限存储
    mapping(address => uint256) private userPermissionBits;
    mapping(bytes32 => uint8) private permissionBitIndex;
    
    /**
     * @dev 使用位操作检查权限,比逐个检查节省大量Gas
     * @param user 用户地址
     * @param permissionIds 权限ID数组
     * @return 权限检查结果的位掩码
     */
    function batchCheckPermissionsBitwise(
        address user,
        bytes32[] calldata permissionIds
    ) external view returns (uint256) {
        uint256 userBits = userPermissionBits[user];
        uint256 result = 0;
        
        for (uint i = 0; i < permissionIds.length && i < 256; i++) {
            uint8 bitIndex = permissionBitIndex[permissionIds[i]];
            if (userBits & (1 << bitIndex) != 0) {
                result |= (1 << i);
            }
        }
        
        return result;
    }
    
    /**
     * @dev 批量权限分配,减少交易次数
     * @param users 用户地址数组
     * @param roleId 要分配的角色ID
     */
    function batchAssignRole(
        address[] calldata users,
        bytes32 roleId
    ) external onlyRole(MODERATOR_ROLE) {
        require(roles[roleId].active, "Role not found");
        
        Role storage role = roles[roleId];
        uint256 roleBits = 0;
        
        // 预计算角色对应的权限位掩码
        for (uint i = 0; i < role.permissions.length; i++) {
            uint8 bitIndex = permissionBitIndex[role.permissions[i]];
            roleBits |= (1 << bitIndex);
        }
        
        // 批量分配给所有用户
        for (uint i = 0; i < users.length; i++) {
            require(userProfiles[users[i]].active, "User not registered");
            userPermissionBits[users[i]] |= roleBits;
            userProfiles[users[i]].updatedAt = block.timestamp;
            emit RoleAssigned(users[i], roleId);
        }
    }
}

前端性能优化

javascript 复制代码
// 实现高效的缓存策略
class OptimizedIdentityManager {
  constructor() {
    this.cache = new Map();
    this.pendingRequests = new Map();
    this.cacheExpiryTime = 5 * 60 * 1000; // 5分钟
  }

  /**
   * 防重复请求的权限检查
   * @param {string} userAddress - 用户地址
   * @param {string} permissionId - 权限ID
   * @returns {Promise<boolean>} 权限检查结果
   */
  async hasPermissionCached(userAddress, permissionId) {
    const cacheKey = `${userAddress}_${permissionId}`;
    
    // 检查缓存
    const cached = this.cache.get(cacheKey);
    if (cached && Date.now() - cached.timestamp < this.cacheExpiryTime) {
      return cached.result;
    }

    // 检查是否有进行中的请求
    if (this.pendingRequests.has(cacheKey)) {
      return await this.pendingRequests.get(cacheKey);
    }

    // 创建新的请求
    const request = this.fetchPermission(userAddress, permissionId);
    this.pendingRequests.set(cacheKey, request);

    try {
      const result = await request;
      
      // 缓存结果
      this.cache.set(cacheKey, {
        result,
        timestamp: Date.now()
      });
      
      return result;
    } finally {
      this.pendingRequests.delete(cacheKey);
    }
  }

  /**
   * 预加载用户权限
   * @param {string} userAddress - 用户地址
   * @param {Array} permissionIds - 权限ID列表
   */
  async preloadPermissions(userAddress, permissionIds) {
    const uncachedPermissions = permissionIds.filter(permissionId => {
      const cacheKey = `${userAddress}_${permissionId}`;
      const cached = this.cache.get(cacheKey);
      return !cached || Date.now() - cached.timestamp >= this.cacheExpiryTime;
    });

    if (uncachedPermissions.length === 0) return;

    // 批量获取权限,而不是逐个请求
    try {
      const results = await this.accessControlManager.batchCheckPermissions(
        userAddress,
        uncachedPermissions
      );

      // 缓存所有结果
      const now = Date.now();
      uncachedPermissions.forEach(permissionId => {
        const cacheKey = `${userAddress}_${permissionId}`;
        this.cache.set(cacheKey, {
          result: results[permissionId],
          timestamp: now
        });
      });
    } catch (error) {
      console.error('预加载权限失败:', error);
    }
  }

  /**
   * 智能缓存清理
   */
  cleanupCache() {
    const now = Date.now();
    for (const [key, value] of this.cache.entries()) {
      if (now - value.timestamp >= this.cacheExpiryTime) {
        this.cache.delete(key);
      }
    }
  }
}

// 使用Web Workers处理密集计算
class CryptographyWorker {
  constructor() {
    this.worker = new Worker('/workers/crypto-worker.js');
    this.messageId = 0;
    this.pendingOperations = new Map();
  }

  /**
   * 在Worker中执行签名验证
   * @param {string} message - 消息
   * @param {string} signature - 签名
   * @param {string} publicKey - 公钥
   * @returns {Promise<boolean>} 验证结果
   */
  async verifySignatureInWorker(message, signature, publicKey) {
    const messageId = ++this.messageId;
    
    return new Promise((resolve, reject) => {
      this.pendingOperations.set(messageId, { resolve, reject });
      
      this.worker.postMessage({
        id: messageId,
        type: 'verifySignature',
        data: { message, signature, publicKey }
      });
      
      // 设置超时
      setTimeout(() => {
        if (this.pendingOperations.has(messageId)) {
          this.pendingOperations.delete(messageId);
          reject(new Error('签名验证超时'));
        }
      }, 10000);
    });
  }

  constructor() {
    // ... 其他初始化代码
    
    this.worker.onmessage = (event) => {
      const { id, result, error } = event.data;
      const operation = this.pendingOperations.get(id);
      
      if (operation) {
        this.pendingOperations.delete(id);
        if (error) {
          operation.reject(new Error(error));
        } else {
          operation.resolve(result);
        }
      }
    };
  }
}

安全考量与最佳实践

关键安全原则

在构建去中心化身份系统时,安全性是最高优先级:

javascript 复制代码
class SecurityManager {
  constructor() {
    this.securityPolicies = {
      maxSessionDuration: 24 * 60 * 60 * 1000, // 24小时
      requiredSignatureStrength: 'high',
      allowedOrigins: process.env.ALLOWED_ORIGINS?.split(',') || [],
      rateLimits: {
        signIn: { maxAttempts: 5, windowMs: 15 * 60 * 1000 }, // 15分钟内最多5次
        permissionCheck: { maxAttempts: 100, windowMs: 60 * 1000 } // 1分钟内最多100次
      }
    };
    
    this.rateLimitStore = new Map();
  }

  /**
   * 验证SIWE消息的安全性
   * @param {Object} parsedMessage - 解析后的SIWE消息
   * @returns {Object} 安全验证结果
   */
  validateMessageSecurity(parsedMessage) {
    const errors = [];
    
    // 检查域名白名单
    if (!this.securityPolicies.allowedOrigins.includes(parsedMessage.domain)) {
      errors.push('域名不在白名单中');
    }
    
    // 检查消息时效性
    const issuedAt = new Date(parsedMessage.issuedAt);
    const now = new Date();
    const messageAge = now - issuedAt;
    
    if (messageAge > 5 * 60 * 1000) { // 5分钟过期
      errors.push('消息已过期');
    }
    
    if (messageAge < -30 * 1000) { // 不能超前30秒
      errors.push('消息时间戳异常');
    }
    
    // 检查nonce格式和长度
    if (!parsedMessage.nonce || parsedMessage.nonce.length < 16) {
      errors.push('Nonce强度不足');
    }
    
    // 检查URI格式
    try {
      new URL(parsedMessage.uri);
    } catch {
      errors.push('URI格式无效');
    }
    
    return {
      isValid: errors.length === 0,
      errors
    };
  }

  /**
   * 速率限制检查
   * @param {string} identifier - 标识符(如IP地址或用户地址)
   * @param {string} action - 操作类型
   * @returns {boolean} 是否允许继续
   */
  checkRateLimit(identifier, action) {
    const policy = this.securityPolicies.rateLimits[action];
    if (!policy) return true;
    
    const key = `${identifier}_${action}`;
    const now = Date.now();
    
    if (!this.rateLimitStore.has(key)) {
      this.rateLimitStore.set(key, { count: 1, windowStart: now });
      return true;
    }
    
    const record = this.rateLimitStore.get(key);
    
    // 重置窗口
    if (now - record.windowStart > policy.windowMs) {
      record.count = 1;
      record.windowStart = now;
      return true;
    }
    
    // 检查是否超出限制
    if (record.count >= policy.maxAttempts) {
      return false;
    }
    
    record.count++;
    return true;
  }

  /**
   * 安全的私钥存储
   * @param {string} privateKey - 私钥
   * @param {string} password - 用户密码
   * @returns {Object} 加密结果
   */
  async encryptPrivateKey(privateKey, password) {
    // 使用WebCrypto API进行客户端加密
    const encoder = new TextEncoder();
    const data = encoder.encode(privateKey);
    
    // 生成盐值
    const salt = crypto.getRandomValues(new Uint8Array(16));
    
    // 从密码派生密钥
    const passwordKey = await crypto.subtle.importKey(
      'raw',
      encoder.encode(password),
      'PBKDF2',
      false,
      ['deriveBits', 'deriveKey']
    );
    
    const aesKey = await crypto.subtle.deriveKey(
      {
        name: 'PBKDF2',
        salt: salt,
        iterations: 100000,
        hash: 'SHA-256'
      },
      passwordKey,
      { name: 'AES-GCM', length: 256 },
      false,
      ['encrypt', 'decrypt']
    );
    
    // 生成随机IV
    const iv = crypto.getRandomValues(new Uint8Array(12));
    
    // 加密私钥
    const encryptedData = await crypto.subtle.encrypt(
      { name: 'AES-GCM', iv: iv },
      aesKey,
      data
    );
    
    return {
      encryptedData: Array.from(new Uint8Array(encryptedData)),
      salt: Array.from(salt),
      iv: Array.from(iv)
    };
  }

  /**
   * 解密私钥
   * @param {Object} encryptedInfo - 加密信息
   * @param {string} password - 用户密码
   * @returns {string} 解密的私钥
   */
  async decryptPrivateKey(encryptedInfo, password) {
    const encoder = new TextEncoder();
    const decoder = new TextDecoder();
    
    // 重建密钥
    const passwordKey = await crypto.subtle.importKey(
      'raw',
      encoder.encode(password),
      'PBKDF2',
      false,
      ['deriveBits', 'deriveKey']
    );
    
    const aesKey = await crypto.subtle.deriveKey(
      {
        name: 'PBKDF2',
        salt: new Uint8Array(encryptedInfo.salt),
        iterations: 100000,
        hash: 'SHA-256'
      },
      passwordKey,
      { name: 'AES-GCM', length: 256 },
      false,
      ['encrypt', 'decrypt']
    );
    
    // 解密
    const decryptedData = await crypto.subtle.decrypt(
      {
        name: 'AES-GCM',
        iv: new Uint8Array(encryptedInfo.iv)
      },
      aesKey,
      new Uint8Array(encryptedInfo.encryptedData)
    );
    
    return decoder.decode(decryptedData);
  }

  /**
   * 生成安全的会话Token
   * @param {Object} payload - 载荷数据
   * @returns {string} JWT Token
   */
  async generateSecureSessionToken(payload) {
    const header = {
      alg: 'HS256',
      typ: 'JWT'
    };
    
    const now = Math.floor(Date.now() / 1000);
    const tokenPayload = {
      ...payload,
      iat: now,
      exp: now + (this.securityPolicies.maxSessionDuration / 1000),
      jti: crypto.randomUUID() // 防重放攻击
    };
    
    const encoder = new TextEncoder();
    const secretKey = await crypto.subtle.importKey(
      'raw',
      encoder.encode(process.env.JWT_SECRET),
      { name: 'HMAC', hash: 'SHA-256' },
      false,
      ['sign']
    );
    
    const headerB64 = btoa(JSON.stringify(header));
    const payloadB64 = btoa(JSON.stringify(tokenPayload));
    const message = `${headerB64}.${payloadB64}`;
    
    const signature = await crypto.subtle.sign(
      'HMAC',
      secretKey,
      encoder.encode(message)
    );
    
    const signatureB64 = btoa(String.fromCharCode(...new Uint8Array(signature)));
    
    return `${message}.${signatureB64}`;
  }
}

部署与运维建议

生产环境配置

javascript 复制代码
// 生产环境配置示例
const productionConfig = {
  // 网络配置
  networks: {
    mainnet: {
      rpc: process.env.MAINNET_RPC_URL,
      contractAddresses: {
        accessControl: process.env.MAINNET_ACCESS_CONTROL_ADDRESS,
        identity: process.env.MAINNET_IDENTITY_ADDRESS
      },
      gasLimit: 500000,
      gasPrice: 'fast' // 使用快速Gas价格
    },
    polygon: {
      rpc: process.env.POLYGON_RPC_URL,
      contractAddresses: {
        accessControl: process.env.POLYGON_ACCESS_CONTROL_ADDRESS,
        identity: process.env.POLYGON_IDENTITY_ADDRESS
      },
      gasLimit: 300000,
      gasPrice: 'standard'
    }
  },
  
  // 安全配置
  security: {
    cors: {
      origin: process.env.ALLOWED_ORIGINS?.split(','),
      credentials: true
    },
    rateLimit: {
      windowMs: 15 * 60 * 1000, // 15分钟
      max: 100, // 每个IP限制100次请求
      message: '请求过于频繁,请稍后重试'
    },
    helmet: {
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          scriptSrc: ["'self'", "'unsafe-inline'"],
          styleSrc: ["'self'", "'unsafe-inline'"],
          imgSrc: ["'self'", "data:", "https:"],
          connectSrc: ["'self'", "wss:", "https:"]
        }
      }
    }
  },
  
  // 监控配置
  monitoring: {
    errorReporting: {
      dsn: process.env.SENTRY_DSN,
      environment: process.env.NODE_ENV
    },
    metrics: {
      endpoint: process.env.METRICS_ENDPOINT,
      interval: 60000 // 每分钟发送一次指标
    }
  }
};

// 部署脚本
const deploymentScript = `
#!/bin/bash

# 构建生产版本
npm run build

# 智能合约部署
npx hardhat deploy --network mainnet --tags AccessControl
npx hardhat deploy --network polygon --tags AccessControl

# 验证合约
npx hardhat verify --network mainnet $MAINNET_CONTRACT_ADDRESS
npx hardhat verify --network polygon $POLYGON_CONTRACT_ADDRESS

# 部署前端到IPFS
ipfs add -r build/
echo "前端已部署到IPFS"

# 更新DNS记录指向新的IPFS哈希
# (这里需要根据具体的DNS服务商API来实现)

echo "部署完成!"
`;

实际应用案例

我们的去中心化身份系统在以下场景中表现出色:

  1. DeFi协议访问控制:用户通过DID登录,根据其持有的代币数量和交易历史自动获得不同等级的访问权限。

  2. DAO治理系统:成员使用去中心化身份参与投票,智能合约自动验证投票权重和资格。

  3. NFT市场身份验证:创作者和收藏家使用DID建立可信身份,增强交易安全性。

  4. 跨链资产管理:用户可以用同一个DID在不同区块链网络上管理资产和权限。

性能数据显示,我们的系统在以太坊主网上的平均Gas消耗为:

  • 用户注册:~85,000 Gas
  • 角色分配:~45,000 Gas
  • 权限检查:~21,000 Gas(只读操作)
  • 批量权限检查:~35,000 Gas(检查10个权限)

相比传统方案,我们的优化减少了约40%的Gas消耗。

总结与展望

去中心化身份代表了数字身份管理的未来方向。通过本文的深入探讨,我们构建了一个完整的Web3身份验证系统,涵盖了从底层密码学到用户界面的各个层面。

核心收获

  1. 技术架构的重要性:合理的架构设计是系统成功的基础,需要在安全性、性能和用户体验之间找到平衡。

  2. 标准化的价值:遵循EIP-4361等行业标准,确保了系统的互操作性和长期可维护性。

  3. 用户体验决定成败:再强大的技术如果用户体验不佳,也难以获得广泛采用。

  4. 安全永远是第一位:在Web3世界中,安全漏洞的代价极其高昂,必须从设计阶段就充分考虑安全因素。

未来发展方向

  1. 跨链身份互操作:随着多链生态的发展,实现真正的跨链身份将成为重要需求。

  2. 零知识身份证明:结合ZK技术,在保护隐私的同时验证身份属性。

  3. 生物特征集成:将生物识别技术与去中心化身份结合,增强安全性。

  4. AI辅助身份管理:利用人工智能自动化身份验证和权限管理流程。

行动建议

对于想要实施去中心化身份系统的开发者和组织:

  1. 从MVP开始:先实现核心功能,再逐步添加高级特性。

  2. 重视社区反馈:用户的真实需求往往比技术规范更重要。

  3. 持续学习:Web3技术发展迅速,保持学习和更新是必要的。

  4. 注重合规:关注各国对数字身份的法规要求,确保合规运营。

去中心化身份不仅仅是技术革新,更是对数字时代个人主权的重新定义。在这个用户真正拥有和控制自己数据的新世界里,我们有机会构建更加公平、透明和以用户为中心的数字生态系统。

未来已来,让我们共同迎接去中心化身份时代的到来。

相关推荐
fs哆哆13 分钟前
在VB.net中,函数:列数字转字母
java·服务器·前端·javascript·.net
追梦人物43 分钟前
Uniswap 流动性机制及相关数学原理分析
区块链
Hilaku1 小时前
别再手写i18n了!深入浏览器原生Intl对象(数字、日期、复数处理)
前端·javascript·代码规范
每天吃饭的羊1 小时前
强制缓存与协商缓存
前端
缘来小哥1 小时前
Nodejs的多版本管理,不仅仅只是nvm的使用
前端·node.js
陈随易1 小时前
Vite和pnpm都在用的tinyglobby文件匹配库
前端·后端·程序员
LeeAt1 小时前
还在为移动端项目组件发愁?快来试试React Vant吧!
前端·web components
鹏程十八少1 小时前
4. Android 用户狂赞的UI特效!揭秘折叠卡片+流光动画的终极实现方案
前端
运维开发王义杰2 小时前
Ethereum: 从 1e+21 到千枚以太币:解密 Geth 控制台的余额查询
web3·区块链
Cache技术分享2 小时前
141. Java 泛型 - Java 泛型方法的类型擦除
前端·后端