区块链2024

avatar
作者
猴君
阅读量:2

项目名称:基于区块链的物资管理系统

技术栈:SpringBoot + SpringSecurity + MyBatis-Plus + MySQL + Redis+ CouchDB + Hyperledger Fabric + RabbitMQ + Docker

项目描述:在自然灾害期间,物资管理常面临信息孤立和不透明等问题。为此,我们采用区块链技术开发了一个灾害救援物资管理系统。该系统通过区块链的分布式账本和智能合约确保物资信息真实、透明且不可篡改。通过实时追踪物资流向,提升了捐赠者和受援者之间的信任,优化了物资分配效率,为有效救援提供了坚实的技术支持。

职责描述: 主要负责登录认证数据上链以及物资追踪模块的开发工作。

1.通过 SpringSecurity 和 JWT 双 token 刷新机制实现用户登录认证和授权。

2.实现物资从入库、运输到分发的整个生命周期管理。编写智能合约代码,打包成链码,安装并部署到区块链网络。通过Java SDK 调用链码, 实现在区块链上记录每一笔物资的流动。

3.通过 Hyperledger Fabric 技术在区块链网络中搭建 peer 节点、orderer节点的集群,实现身份和权限的校验,将交易列表排序并打包成区块,最后通过PBFT共识算法决定区块是否上链。

4.利用 Redis 缓存热点数据,优化了频繁的物资和用户信息查询,显著降低了数据库负载并提高了系统响应速度。

5.使用 RabbitMQ 异步处理数据上链请求,利用 RabbitMQ 的发布订阅模型,在物资入库、运输到达等关键流程节点自动触发更新通知。

6.客户端通过调用智能合约的查询接口来获取物资的溯源信息,并以列表的形式呈现物资的流通路径和历史记录。

登录模块:

1.SpringSecurity 和 JWT 双 token流程

用户首次登录时,我们将用户名密码封装到UsernamePasswordAuthenticationToken对象当中,其次需要实现UserDetailsService接口并重写loadUserByUsername根据用户名获取用户信息,最后我们会调用AuthenticationManager对象的authenticate方法并传入封装了用户名密码的UsernamePasswordAuthenticationToken对象,内部会比较前端传入的用户名密码和数据库查询的用户名密码是否一致。

如果一致就登陆成功,这个时候会将用户信息权限信息封装到一个LoginUser对象当中并缓存到Redis。同时根据用户id生成双token,access_token用于免登录的认证,refresh_token用于刷新过期时间,refresh_token缓存到redis。用户再次访问资源时会先携带access_token,拦截器会对请求进行拦截并判断access_token是否合法是否过期,过期的话就会通知前端,前端会携带refresh_token再次发送请求,refresh_token没有过期就会刷新双token的过期时间,采用的是先删除redis中refresh_token,然后根据JWT生成俩个全新的双token,将新的refresh_token缓存到redis并将新的双token响应给前端。

2.为什么使用双token,有什么好处?

单token存在一些缺陷,过期时间设置太短比如30分钟,用户的体验就很差。过期时间设置太长,token就容易被盗取不安全。双token可以实现用户在access_token过期后,通过refresh_token来续期,用户体验好,同时刷新也保证了安全性(每次刷新会创建全新的token)。

区块链基础

1.如何实现防止数据篡改的?

区块链的不可篡改性是通过使用加密哈希函数共识算法去中心化的网络结构区块确认机制来实现的。这些机制共同确保一旦数据被添加到区块链中,就无法被更改或删除。

区块链基本单位是区块,区块由区块头和区块体组成。

区块头保存了上一个区块的区块哈希,相当于指针;还保存了当前区块的一个merkle树的根哈希值,防止数据篡改就是通过这个merkle树来保证的。merkle树构建过程:区块体保存交易列表,我们计算每个交易数据的hash值并两两组合再次计算哈希值,最终就得到了merkle树的根hash值。后期如果我们需要获取该区块的交易信息,就会提前验证数据是否被篡改,验证方式就是对获取的区块交易列表重新构建merkle树得到一个根hash值,然后和原来的根hash进行对比,如果一致就代表没有被篡改,不一致就代表被篡改了。

你知道哪些哈希函数的构造方法呢?解决哈希冲突有哪些方法呢?

哈希函数构造方法:除留取余法 直接定址法 平方取中法 数字分析法 折叠法

哈希冲突解决方法:链地址法 开放定址法(线性探测 平方探测) 再哈希法 建立公共溢出区

https://blog.csdn.net/weixin_46486402/article/details/139132744

常见的对称加密和非对称加密有哪些?

对称加密
  • 定义:使用相同的密钥进行加密和解密。
  • 常见算法
    • AES(Advanced Encryption Standard):广泛应用,提供128、192、256位密钥。
    • DES(Data Encryption Standard):已被AES取代,使用56位密钥。
    • 3DES(Triple DES):对DES进行三次加密,提高安全性。
    • Blowfish:密钥长度可变(32-448位),适用于大数据量加密。
    • RC4:流加密算法,简单且快速,但已不推荐使用。
非对称加密
  • 定义:使用一对密钥(公钥和私钥)进行加密和解密。
  • 常见算法
    • RSA(Rivest-Shamir-Adleman):广泛用于安全通信和数字签名,高安全性但速度较慢。
    • ECC(Elliptic Curve Cryptography):提供高安全性和高效能,使用椭圆曲线提供相同安全性的密钥长度较短。
    • DSA(Digital Signature Algorithm):主要用于数字签名,基于离散对数问题。
    • Diffie-Hellman:用于安全密钥交换,不直接用于加密和解密。

总结

  • 对称加密适用于需要速度和效率的数据传输场景。
  • 非对称加密适用于密钥交换、数字签名等需要高安全性的场景。

2.如何保证不同组织账本数据一致性?

通过fabric网络中的orderer节点的共识机制来保证。PBFT拜占庭,超过2/3组织数通过提案就广播并将新的区块加入到各个组织的本地区块链账本当中。

3.智能合约有什么作用?

编写数据上链(增删改)操作 和 数据追踪(区块链区块历史记录查询) 的API接口,以及库存等判断。

4.CouchDB有什么用?

用来存储本地区块链账本数据的副本,因为区块链是链表,查询效率低,CouchDB是一个分布式的文档型数据库, 区块链数据通常以JSON格式进行存储和交换,而CouchDB天生支持JSON文档的存储和查询。这使得CouchDB能够直接存储区块链数据而无需进行复杂的数据转换,简化了开发和集成的过程。CouchDB具有灵活的MapReduce查询引擎,可以对存储在其中的JSON文档进行复杂的查询和分析操作。这使得开发人员可以方便地进行区块链数据的查询和分析。

将CouchDB用于存储区块链副本而不是MySQL有几个原因:

  1. 分布式设计: CouchDB是一个分布式的文档型数据库,具有内置的复制和分片功能。这使得它可以轻松地实现区块链副本的分布式存储和复制,从而提高了系统的可用性和可靠性。相比之下,MySQL通常是单节点部署,需要额外的复制和分片方案来实现分布式存储,这增加了部署和维护的复杂性。
  2. JSON文档存储: 区块链数据通常以JSON格式进行存储和交换,而CouchDB天生支持JSON文档的存储和查询。这使得CouchDB能够直接存储区块链数据而无需进行复杂的数据转换,简化了开发和集成的过程。
  3. MapReduce查询引擎: CouchDB具有灵活的MapReduce查询引擎,可以对存储在其中的JSON文档进行复杂的查询和分析操作。这使得开发人员可以方便地进行区块链数据的查询和分析,从而实现更丰富的功能和应用。
  4. 高并发和扩展性: CouchDB的设计目标之一是高并发和水平扩展,可以轻松地处理大规模的数据和请求。这使得它适用于存储区块链副本,能够应对不断增长的区块链数据和用户请求。

综上所述,CouchDB作为一种分布式、灵活和高性能的文档型数据库,非常适合用于存储区块链副本。它提供了简单的部署和维护方式,同时具备强大的查询和扩展能力,能够满足区块链系统对于高可用性、可靠性和性能的要求。

数据上链及物资追踪模块

1.代码层面的实现过程

实现物资从入库、运输到分发的整个生命周期管理。编写智能合约代码,打包成链码,安装并部署到区块链网络。通过Java SDK 调用链码, 实现在区块链上记录每一笔物资的流动,确保物资的追溯可靠性和供应链的透明度,以提高捐赠者和受赠者的信任度。

2.Fabric网络架构

一个Fabric网络通常包含多个组织

每个组织有多个Peer节点,共享一个或多个Orderer节点来提供交易排序和区块打包服务。

peer节点又分为 背书节点 和 commit提交节点,其中背书节点用于提案(上链数据的操作)的身份验证 权限验证 以及交易的有效性,不同组织的背书策略不同;commit节点负责验证区块交易有效性,共识通过就将区块加入到该组织本地区块链上。

Orderer节点可以属于一个单独的Orderer组织,或由多个组织共享,不必每个组织都有。orderer节点用于对验证通过的交易列表进行排序并打包成区块,然后进入共识阶段,将区块广播给其他组织的peer的commit节点进行验证,只有有足够多的节点通过了这个提案达成共识,当前的orderer节点就会将这个提案通过的信息广播给所有组织,这样,所有组织(通过commit节点)都会将区块加入的各自本地的区块链账本上,保证了不同组织区块链账本数据的一致性。

Fabric搭建步骤搭建流程

  1. 生成加密材料:使用cryptogen工具生成组织的MSP(身份校验 授权)和TLS(数据加密)材料。
  2. 配置configtx.yaml:定义组织的MSP和策略信息。
  3. 配置docker-compose.yaml:定义并启动OrdererPeer节点。
  4. 创建并加入通道:使用CLI命令创建通道并让各个Peer节点加入通道。
  5. 部署智能合约:编写、打包、安装并提交智能合约。
  6. 调用智能合约:通过Fabric SDK调用智能合约,实现业务逻辑。

3.结合Fabric网络实现数据上链的过程:

在一个物资管理系统中,假设有多个组织参与,每个组织都有自己的Peer节点和Orderer节点,彼此之间通过Hyperledger Fabric网络进行通信。以下是物资入库操作的整个过程:

  1. 客户端发起交易请求

    • 首先,某个组织的客户端(例如物资管理系统的用户)会发起一个物资入库的交易请求,请求将某批物资入库到系统中。
  2. 交易传递到客户端的Peer节点

    • 客户端所属组织的Peer节点会接收到该交易请求。
  3. 背书策略

    • 在交易被写入区块链之前,需要经过背书阶段。这个阶段涉及到与参与背书的各个组织的智能合约的交互。对于物资入库操作,可能会有多个组织参与背书,确保交易的有效性。
  4. 背书结果提交给客户端的Orderer节点

    • 一旦交易得到了足够的背书,客户端的Peer节点会将背书结果提交给所属组织的Orderer节点。
  5. Orderer节点进行排序和打包

    • Orderer节点负责将接收到的交易按照顺序打包成区块,并进行排序。
  6. 区块传递给各个组织的Peer节点

    • 一旦形成了新的区块,Orderer节点会将该区块传递给各个组织的Peer节点。
  7. 共识过程

    • 在交易被验证后,会进入共识阶段。在这个阶段,Orderer节点会协调各个Peer节点就交易进行共识,以确保所有节点都同意将该交易写入区块链。这个共识过程通常涉及到拜占庭容错算法(如Kafka或Raft)或其他共识机制,以确保网络中的每个节点都达成一致意见。
  8. 提交到本地账本

    • 一旦交易通过共识,Orderer节点会将交易打包成区块,并将区块广播给所有Peer节点。然后,每个Peer节点会将收到的区块验证后写入本地账本。这样做是为了确保每个节点都有一份完整且一致的账本副本,以保持系统的一致性和可靠性。

4.追踪模块的实现:

客户端可以通过调用区块链上的智能合约或者使用专门的查询接口来查询物资的溯源信息。这些接口可能会提供按照物资编号、生产日期、流通路径等条件进行查询,并返回相应的物资信息及其历史记录 交易的事务id。

数据可视化:获取到的物资溯源信息可以被客户端应用程序进行处理和展示。可以通过数据可视化的方式,以图表、列表等形式呈现物资的流通路径和历史记录,使用户能够清晰地了解物资的来源和去向。

溯源信息:

溯源信息则更加全面和深入,它不仅包括流通路径的信息,还包括关于物资本身的详细数据,如生产批次、生产日期、成分或原料来源等。溯源信息的目的是提供足够的信息来追踪物资回到其原始来源,这在食品安全、药品监管和高价值商品中尤其重要。它有助于验证物资的真实性和质量,确保符合安全标准。

RabbitMQ

1. 异步处理数据上链请求

物资信息更新到区块链是一个资源密集型的过程,可能需要一些时间来完成。使用 RabbitMQ,您可以将数据上链的请求异步处理:

  • 生产者:应用服务器接收到上链请求后,不直接调用区块链服务,而是将这些请求作为消息发送到 RabbitMQ。
  • 消费者:后端服务作为消费者从队列中拉取消息,并处理数据上链的过程,然后将结果通知到前端或进行日志记录。
  • 这种方式可以减少用户等待时间,提高用户体验,并通过背景处理提升系统的整体性能。

2. 事件驱动的通知

在物资管理和分发过程中,各个阶段完成后需要通知相关的利益相关者(如供应商、受赠者、监管机构等):

  • 使用 RabbitMQ 发布订阅模型,系统可以在完成如物资入库、运输、到达等关键节点时,发布消息到不同的消息通道。
  • 各利益相关者通过订阅相关通道,可以即时收到更新,从而做出响应或进行下一步操作。

消息队列

熟悉 RabbitMQ 的使用,有处理消息丢失重复消费消息顺序性问题,以及延迟队列的实现的实战经验。

1.RabbitMQ-如何保证消息不丢失?(重要)

主要从三个层面考虑:

第一个是开启生产者确认机制,确保生产者的消息能到达队列,如果报错可以先记录到日志中,再去修复数据。

第二个是开启持久化功能,确保消息未消费前在队列中不会丢失,其中的交换机、队列、和消息都要做持久化。

第三个是开启消费者确认机制为auto,由spring确认消息处理成功后完成ack,当然也需要设置一定的重试次数,我们当时设置了3次,如果重试3次还没有收到消息,就将失败后的消息投递到异常交换机,交由人工处理。

2.RabbitMQ消息的重复消费问题如何解决的?(重要)

消费者是设置了自动确认机制,当服务还没来得及给MQ确认的时候,服务宕机了,导致服务重启之后,又消费了一次消息。这样就重复消费了

因为我们当时处理的支付(订单|业务唯一标识),它有一个业务的唯一标识,我们再处理消息时,先到数据库查询一下,这个数据是否存在,如果不存在,说明没有处理过,这个时候就可以正常处理这个消息了。如果已经存在这个数据了,就说明消息重复消费了,我们就不需要再消费了。

其实这个就是典型的幂等的问题,比如,redis分布式锁、数据库的锁都是可以的解决这个问题的。

3.其他的解决方案吗?

4.RabbitMQ中死信交换机 ? (RabbitMQ延迟队列有了解过嘛)(重要)

延迟队列就是用到了死信交换机和TTL(消息存活时间)实现的。

如果消息超时未消费就会变成死信,在RabbitMQ中如果消息成为死信,队列可以绑定一个死信交换机,在死信交换机上可以绑定其他队列,在我们发消息的时候可以按照需求指定TTL的时间,这样就实现了延迟队列的功能了。

我记得RabbitMQ还有一种方式可以实现延迟队列,在RabbitMQ中安装一个死信插件,这样更方便一些,我们只需要在声明交互机的时候,指定这个就是死信交换机,然后在发送消息的时候直接指定超时时间就行了,相对于死信交换机+TTL要省略了一些步骤。

5.如果有100万消息堆积在MQ , 如何解决 ?

我在实际的开发中,没遇到过这种情况,不过,如果发生了堆积的问题,解决方案也所有很多的

第一:提高消费者的消费能力 ,可以使用多线程消费任务

第二:增加更多消费者,提高消费速度

使用工作队列模式, 设置多个消费者消费消费同一个队列中的消息

第三:扩大队列容积,提高堆积上限

可以使用RabbitMQ惰性队列,惰性队列的好处主要是

①接收到消息后直接存入磁盘而非内存

②消费者要消费消息时才会从磁盘中读取并加载到内存③支持数百万条的消息存储

6.RabbitMQ的高可用机制有了解过嘛?

我们当时项目在生产环境下,使用的集群,当时搭建是镜像模式集群,使用了3台机器。镜像队列结构是一主多从,所有操作都是主节点完成,然后同步给镜像节点,如果主节点宕机后,镜像节点会替代成新的主节点,不过在主从同步完成前,主节点就已经宕机,可能出现数据丢失。

7.那出现丢数据怎么解决呢?

我们可以采用仲裁队列,与镜像队列一样,都是主从模式,支持主从数据同步,主从同步基于Raft协议,强一致。并且使用起来也非常简单,不需要额外的配置,在声明队列的时候只要指定

这个是仲裁队列即可。

8.RabbitMQ,实现消息的异步解耦?

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!