基于 Spring Boot + Hyperledger Fabric 的数字版权交易与链上存证系统
| 项 | 建议 |
|---|---|
| 标题 | 基于 Spring Boot + Hyperledger Fabric 的数字版权交易与链上存证系统 |
| 标签 | Spring Boot, Vue3, Hyperledger Fabric, 区块链存证, 数字版权, 毕业设计 |
| 类型 | 原创 |
| 分类 | 后端 / 区块链 |
| 源码 | https://gitee.com/song-ri/digital-copyright-trading |
正文
本文介绍一个完整的数字版权交易与存证溯源系统:Spring Boot + Vue3 搭建业务平台,Hyperledger Fabric 实现审核通过后的链上锚定,支持公开验真与版权溯源。完整源码已开源至 Gitee。
前言
数字作品(图片、文档、设计稿等)具有易复制、易篡改、权属难举证的特点。传统交易平台往往只记录「谁买了什么」,缺少可验证的内容存证链条。
本项目的设计思路是:
链下保存原文件 + 链上锚定内容指纹哈希
既不把大文件塞进区块链(成本高、隐私差),又能通过密码学哈希实现「事后可验真、难篡改」的存证能力。整套系统覆盖:登记 → 审核 → 上链 → 挂牌 → 交易 → 验真全流程。
开源地址:https://gitee.com/song-ri/digital-copyright-trading
一、技术栈
| 层次 | 技术选型 |
|---|---|
| 前端 | Vue 3、Vite、Pinia、Vue Router |
| 后端 | Spring Boot 3、Spring Security、JWT |
| 数据库 | MySQL 8 |
| 区块链 | Hyperledger Fabric + Go 链码 |
| 通信 | REST API、WebSocket(消息通知) |
二、系统架构
整体采用「Web 业务层 + 异步锚定 + 联盟链」的分层架构:
┌─────────────────────────────────────────────┐ │ Vue3 前端 │ │ 登记作品 / 市场挂牌 / 公开验真 / 管理后台 │ └──────────────────┬──────────────────────────┘ │ REST API + JWT ┌──────────────────▼──────────────────────────┐ │ Spring Boot 业务层 │ │ 作品 · 挂牌 · 订单 · 审核 · 投诉 · 分润 │ └──────────────────┬──────────────────────────┘ │ WorkApprovedEvent(异步) ┌──────────────────▼──────────────────────────┐ │ BlockchainAnchorService │ │ mock 模式(本地演示)/ fabric 模式(真实上链)│ └──────────────────┬──────────────────────────┘ │ Fabric Gateway (gRPC + TLS) ┌──────────────────▼──────────────────────────┐ │ Hyperledger Fabric │ │ 通道 mychannel · 链码 copyright_attestation │ └──────────────────┬──────────────────────────┘ │ ┌──────────────────▼──────────────────────────┐ │ MySQL │ │ users / copyright_works / marketplace_listings / trade_orders │ └─────────────────────────────────────────────┘三层保护机制
| 层级 | 机制 | 作用 |
|---|---|---|
| 内容指纹 | 上传后生成sha256:... | 把数字文件绑定为唯一可比对的标识 |
| 平台审核 | 管理员 PENDING → APPROVED/REJECTED | 人工把关登记内容是否合规 |
| 链上存证 | 审核通过后调用Anchor(workId, hash) | 证明某时刻平台认定的指纹已被记录,事后可验真 |
重要:链上不存图片/文档原文件,只存
SHA256(指纹字符串)的 64 位十六进制哈希。
三、核心业务流程
3.1 作品登记:自动生成内容指纹
用户登录后上传源文件或展示图,后端自动计算 SHA-256 指纹:
// CopyrightWorkService — 指纹计算(简化)if(file!=null){rawFp="sha256:"+sha256Hex(file.getBytes());}elseif(!gallery.isEmpty()){rawFp="sha256:"+sha256Hex(gallery.get(0).getBytes());}work.setContentFingerprint(normalize(rawFp));// 例:sha256:e18d6060...work.setAuditStatus(AuditStatus.PENDING);// 待审核,尚未上链若库内已有相同指纹,系统返回 HTTP 409 并列出重复作品,用户确认后可继续登记。
3.2 管理员审核:通过后触发异步上链
审核通过时,在事务内更新状态并发布 Spring 事件;事务提交后,异步监听器执行链上锚定:
// 审核通过work.setAuditStatus(AuditStatus.APPROVED);workRepository.save(work);eventPublisher.publishEvent(newWorkApprovedEvent(workId));// 异步监听器 @Async + @TransactionalEventListener(AFTER_COMMIT)blockchainAnchorService.anchorApprovedWork(event.getWorkId());这样设计的好处:审核事务与上链解耦,Fabric 网络异常不会回滚审核结果,失败信息写入blockchain_anchor_error字段,支持手动重试。
3.3 Java 侧:Fabric Gateway 提交交易
后端通过 Fabric Gateway SDK 连接 Peer,调用链码Anchor函数:
Contractcontract=network.getContract(chaincodeName);Proposalproposal=contract.newProposal("Anchor").addArguments(String.valueOf(workId),contentHashHex).build();Transactiontxn=proposal.endorse();// 背书txn.submit();// 提交至 Ordererreturntxn.getTransactionId();// 写入 blockchain_tx_hash其中contentHashHex = SHA256(指纹字符串),64 位小写十六进制。
3.4 Go 链码:copyright_attestation
链码非常精简,只有两个函数:
// Anchor — 写入世界状态 WORK_<workId> → 64位hexfunc(s*SmartContract)Anchor(ctx contractapi.TransactionContextInterface,workIdstring,contentHashHexstring)error{key:="WORK_"+strings.TrimSpace(workId)returnctx.GetStub().PutState(key,[]byte(strings.ToLower(contentHashHex)))}// GetAnchor — 只读查询,不修改账本func(s*SmartContract)GetAnchor(ctx contractapi.TransactionContextInterface,workIdstring)(string,error){b,err:=ctx.GetStub().GetState("WORK_"+workId)ifb==nil{return"",nil}returnstring(b),nil}3.5 挂牌交易:购买后版权主体转移
审核通过的作品可挂牌出售。买家下单后:
- 挂牌状态
ACTIVE → SOLD - 作品
owner变更为买家 - 生成
TradeOrder(状态 COMPLETED) - 异步记录分润(RoyaltyService)
3.6 公开验真:三方交叉比对
验真页面(/verify)支持三种输入方式:
- 按作品 ID 查询
- 粘贴指纹字符串
- 上传文件重新计算指纹
验真通过需同时满足:
verified = 作品 audit_status == APPROVED AND 库中有 blockchain_tx_hash AND 链上 GetAnchor(workId) == SHA256(库内指纹) AND(若提交文件/指纹)与库内记录一致验真通过说明:文件内容与平台登记、链上存证一致,但不等于自动证明「登记人即著作权人」(论文/答辩中需如实说明边界)。
四、核心逻辑伪代码
以下伪代码与源码一一对应,便于理解各模块状态迁移规则。
4.1 登录接口(ApiAuthController)
SESSION_STATE = Unauthenticated / Authenticated ACCOUNT_STATE = Disabled / Enabled function 用户登录(username, password): if 参数非法: return HTTP 400 try: auth = AuthenticationManager.authenticate(...) catch: return HTTP 401 if 账号 Disabled: return HTTP 403 accessToken = JwtService.createToken(user) return { accessToken, user } function 请求鉴权(request): token = Header "Authorization: Bearer ..." if token 有效 AND 账号 Enabled: SESSION_STATE = Authenticated else: 对受保护接口返回 HTTP 4014.2 购买交易(TradeService)
LISTING_STATE = ACTIVE / SOLD / CANCELLED WORK_AUDIT_STATE = PENDING / APPROVED / REJECTED function 购买交易(buyer, listingId): listing = 查询挂牌(listingId) if listing.status != ACTIVE: 抛出异常 if work.auditStatus != APPROVED: 抛出异常 if buyer == seller: 抛出异常「不能购买自己的作品」 listing.status = SOLD work.owner = buyer order = 新建 TradeOrder(status=COMPLETED) RoyaltyService.calculateAndRecordRoyalty(order) return order4.3 前端登录提交(LoginView.vue)
function 登录提交(): try: await AuthStore.login(username, password) Router.push(redirect 或 "/catalog") catch e: if e.status == 403: 清空 localStorage Token 展示友好错误信息 function AuthStore.login(username, password): response = POST "/api/auth/login" localStorage.setItem(TOKEN_KEY, response.accessToken)4.4 管理员审核(AdminWorkReviewService)
AUDIT_STATE = PENDING / APPROVED / REJECTED ANCHOR_STATE = NotAnchored / Anchored / AnchorFailed function 管理员审核通过(admin, workId): work.auditStatus = APPROVED 保存(work) 发布 WorkApprovedEvent(workId) function 管理员审核驳回(admin, workId, remark): work.auditStatus = REJECTED 取消该作品全部 ACTIVE 挂牌 // 不发布上链事件 function 监听审核通过(event): result = BlockchainAnchorService.anchorApprovedWork(workId) if result.success: ANCHOR_STATE = Anchored else: ANCHOR_STATE = AnchorFailed4.5 内容指纹登记(CopyrightWorkService)
function 登记作品(owner, file, images, manualFingerprint): rawFp = computeRawFingerprint(...) // 文件 / 图集 / 手动三选一 fingerprint = normalize("sha256:" + hex) if 库内重复 AND 用户未确认: return HTTP 409 work = 新建 CopyrightWork(auditStatus=PENDING, fingerprint) 保存(work) // 此时:有指纹、待审核,尚未上链4.6 异步链上锚定(BlockchainAnchorService)
function 锚定已审核作品(workId): if work.blockchainTxHash 非空: return Ok() // 幂等 if work.contentFingerprint 为空: return Fail() hashHex = SHA256(fingerprint字符串) if BLOCKCHAIN_MODE == fabric: txId = FabricGatewayClient.anchor(workId, hashHex) else: txId = mockAnchor(workId, fingerprint) persistAnchor(workId, txId)4.7 Fabric 网关(FabricGatewayClient)
function anchor(workId, contentHashHex): gw = 获取Gateway() // 懒加载 + TLS + User1 身份 contract = network.getContract("copyright_attestation") proposal = contract.newProposal("Anchor") .addArguments(str(workId), contentHashHex) txn = proposal.endorse() txn.submit() return txn.getTransactionId() function getAnchor(workId): return contract.evaluateTransaction("GetAnchor", str(workId))4.8 公开验真与溯源(BlockchainVerificationService)
function buildReport(work, submittedFingerprint, file): expectedChainHash = SHA256(work.contentFingerprint) chainHash = FabricGatewayClient.getAnchor(work.id) chainMatchesDb = (expectedChainHash == chainHash) verified = 已审核 AND 已锚定 AND chainMatchesDb AND 文件一致 function 溯源聚合(workId): timeline = [REGISTER, AUDIT_APPROVE, BLOCKCHAIN_ANCHOR, LISTING, ...] 按时间排序返回 TraceReport五、数据库设计
四张核心业务表及其关系:
users ──< copyright_works (owner_id) copyright_works ──< marketplace_listings (work_id) marketplace_listings ──< trade_orders (listing_id) users ──< trade_orders (buyer_id)copyright_works表关键字段:
| 字段 | 说明 |
|---|---|
content_fingerprint | 内容指纹,如sha256:e18d6060... |
audit_status | PENDING / APPROVED / REJECTED |
blockchain_tx_hash | Fabric 交易 ID |
blockchain_network | 如fabric-mychannel:copyright_attestation |
blockchain_anchored_at | 上链时间 |
blockchain_anchor_error | 上链失败原因(可重试) |
完整建表 SQL 见仓库src/main/resources/db/mysql-init.sql。
六、Fabric 部署与双模式切换
项目支持两种区块链模式,通过环境变量BLOCKCHAIN_MODE切换:
| 模式 | 说明 | 适用场景 |
|---|---|---|
mock | 本地模拟交易 ID,无需 Fabric | 开发调试、演示答辩 |
fabric | 真实连接 VM 上的 Fabric Peer | 生产/真实上链 |
Fabric 模式配置示例(application.yml):
app:blockchain:enabled:truemode:fabricfabric:grpc-target:192.168.x.x:7051tls-enabled:truetls-root-cert-file:C:/fabric-crypto/org1/ca.crtclient-cert-file:C:/fabric-crypto/org1/user1-cert.pemclient-key-file:C:/fabric-crypto/org1/user1-key.pemmsp-id:Org1MSPchannel-name:mychannelchaincode-name:copyright_attestation部署步骤(VM 侧):
- 启动 Fabric test-network,创建通道
mychannel - lifecycle 部署链码
copyright_attestation - 导出 Org1 User1 证书到本机
- 启动 Spring Boot,管理员审核通过一个作品即可触发上链
详细脚本见仓库fabric/deploy/README.md。
七、本地快速启动
# 1. 初始化数据库mysql-uroot-p<src/main/resources/db/mysql-init.sql# 2. 无 Fabric 时用 mock 模式setBLOCKCHAIN_MODE=mock# 3. 启动后端mvn spring-boot:run# 4. 启动前端cdfrontend&&npminstall&&npmrun dev| 地址 | 说明 |
|---|---|
| http://localhost:5173 | 前端 |
| http://localhost:8080 | 后端 API |
| admin / admin123 | 默认管理员(首次启动自动创建) |
完整演示流程:
- 注册/登录 → 登记作品(上传文件)
- 管理员审核通过 → 自动上链(或 mock 模拟)
- 「我的作品」→ 去挂牌 → 设价
- 其他用户购买 → 版权转移
- 导航栏「验真」→ 输入作品 ID 或上传文件验证
八、项目亮点
- 链下指纹 + 链上哈希:原文件不上链,兼顾隐私与成本
- 审核驱动上链:避免无效数据写入账本
- 异步事件架构:审核与上链解耦,失败可重试
- 三方验真:库内指纹、链上哈希、上传文件交叉比对
- 指纹撞库预警:重复登记治理与风险提示
- 真实 Fabric 对接:非纯 Mock,含 VM 部署脚本与 Gateway 客户端
九、研究边界
系统能做到:
- 内容防篡改举证(验真通过 = 文件与登记、链上一致)
- 登记—审核—存证—交易的平台闭环
- 版权交易后的权利人变更记录
系统不能单独做到:
- 自动识别抄袭、冒领、跨平台侵权
- 链上或平台单方面裁决著作权归属
- 同一文件被多人登记时的法律效力排序
十、目录结构
digital-copyright-trading/ ├── frontend/ # Vue3 前端 │ └── src/views/VerifyView.vue # 公开验真页 ├── src/main/java/ # Spring Boot 后端 │ ├── fabric/ # FabricGatewayClient │ └── service/ # 锚定、验真、溯源服务 ├── fabric/ │ ├── chaincode/copyright_attestation/ # Go 链码 │ └── deploy/ # VM/Windows 部署脚本 └── src/main/resources/db/ # MySQL 初始化脚本总结
本项目将 Web 版权交易平台与 Hyperledger Fabric 联盟链结合,通过「内容指纹 + 审核驱动异步锚定 + 公开验真」构建了一套可落地的数字版权保护闭环。适合作为区块链应用、数字版权管理方向的毕业设计或实战学习参考。
完整源码:https://gitee.com/song-ri/digital-copyright-trading
如果本文对你有帮助,欢迎点赞 + 收藏!部署或二次开发中遇到问题,欢迎在评论区交流。
