教程区块链区块链技术ch1515.6 设计 REST API 与前端界面

本页目录

联盟链前端不是 DApp——用户通常不直接管理私钥,由后端服务代为签名。REST API 是联盟链应用的标准接口模式。


15.6.1 架构模式

graph LR
    User[用户浏览器] --> Frontend[React/Vue 前端]
    Frontend --> |HTTP| API[Express/Fastify REST API]
    API --> |Gateway| Fabric[Fabric 网络]
    API --> Auth[认证层]
    
    style API fill:#e3f2fd
    style Fabric fill:#c8e6c9

身份模式对比

模式谁签名场景
服务代签后端持有组织 admin 私钥物流、溯源、监管系统
多级权限用户登录 → 后端按角色转发内部系统
客户端证书用户自带 x.509高安全需求

15.6.2 REST API 设计

typescript
/**
 * Express 路由:资产溯源 API
 */
import express from 'express';
import { FabricClientService } from '../fabric-client';

const router = express.Router();

// 资产 CRUD
router.get('/assets/:id', async (req, res) => {
  const asset = await fabric.getAsset(req.params.id);
  res.json(asset);
});

router.post('/assets', authenticate, authorize('admin'), async (req, res) => {
  const { id, color, size, owner } = req.body;
  const txId = await fabric.createAsset({ id, color, size, owner, appraisedValue: 0 });
  res.status(201).json({ transactionId: txId, status: 'submitted' });
});

router.put('/assets/:id/transfer', async (req, res) => {
  const { newOwner, reason } = req.body;
  const txId = await fabric.transferAsset(req.params.id, newOwner);
  res.json({ transactionId: txId, newOwner, reason });
});

// 溯源查询:时间线
router.get('/assets/:id/history', async (req, res) => {
  const history = await fabric.getAssetHistory(req.params.id);
  // 返回按时间排序的变更事件
  res.json(history.map(h => ({
    txId: h.txId,
    timestamp: h.timestamp,
    owner: h.value.owner,
    change: h.isDelete ? 'deleted' : 'modified',
  })));
});

15.6.3 前端界面设计

graph TD
    U[用户] --> List[资产列表页]
    List --> Detail[资产详情页]
    Detail --> History[变更历史时间线]
    Detail --> Transfer[转移操作]
    Transfer --> Confirm[确认弹出框]
    Confirm --> TxResult[交易结果]
    
    style List fill:#e3f2fd
    style Detail fill:#e8f5e9

界面要点

  • 权限感知 UI:管理员看到"创建"按钮,普通用户只读
  • 交易状态轮询:显示 "待确认" → "已提交" → "已出块"
  • 时间线可视化:用时间线组件展示资产从出厂到现在的流转路径
  • 二维码/批次码:扫码查询资产

15.7 权限控制与私有数据集合


15.7.1 私有数据集合(Private Data Collection)

联盟链中,并非所有数据都应对所有参与者可见。私有数据集合让敏感字段仅对特定组织可见,同时其公共哈希上链防篡改。

graph TB
    subgraph Public["公共数据(所有组织可见)"]
        P1[资产ID, 所有者, 公共状态]
        P2[公共哈希 = keccak256(私有数据)]
    end
    
    subgraph Private["私有数据(仅 Org1 可见)"]
        D1[价格, 供应商, 内部评级]
        D2[存储于 Org1 的私有数据状态数据库]
    end
    
    P2 -.-> |防篡改| D1
    
    style Private fill:#e8f5e9
    style Public fill:#fff3e0

集合定义

yaml
# collections_config.json
[
  {
    "name": "assetPrivateDetails",
    "policy": "OR('Org1MSP.member')",
    "requiredPeerCount": 1,
    "maxPeerCount": 1,
    "blockToLive": 0,
    "memberOnlyRead": true,
    "endorsementPolicy": {
      "signaturePolicy": "OR('Org1MSP.peer', 'Org2MSP.peer')"
    }
  }
]

15.7.2 访问控制策略

层次机制控制点
网络层TLS 证书 + 通道隔离节点能否加入网络
链码层GetMSPID() 检查调用者的组织身份
数据层私有集合 policy谁能看到私有数据
应用层RBAC 角色系统用户权限映射
go
// 链码层检查
func (s *SmartContract) ConfidentialOperation(ctx contractapi.TransactionContextInterface, ...) error {
    mspID, _ := ctx.GetClientIdentity().GetMSPID()
    
    if mspID != "Org1MSP" && mspID != "Org2MSP" {
        return fmt.Errorf("unauthorized: %s", mspID)
    }
    
    // 继续执行...
    return nil
}

> ← 15.5 SDK 后端 | 本章最后一节已合并 |*

评论

0

评论加载中…

发表评论

0/2000