Fabric-CA是Hyperledger Fabric自带的证书管理工具,对于开发和测试非常方便。在这个教程中我们将探索Fabric-CA的使用方法并利用它完成用户的注册/Register和登记/Enrollment。
Hyperledger Fabric是一个许可制的区块链平台,在访问Fabric网络之前必须先进行身份识别并获得访问许可。Fabric网络中的身份是使用数字证书实现的,因此需要CA来处理证书的管理。
虽然Hyperledger Fabric允许使用第三方CA软件来管理用户证书,但出于方便考虑也自带了一个Fabric CA工具可以作为Fabric网络中的CA。由于Fabric自带的应用实例都是使用Fabric CA,因此我们在这个教程中将探索Fabric CA,特别是它在用户注册登记中的应用。
在这片文章中,我们使用部署在First网络上的Fabcar应用,这个实例应用包含了链码和客户端应用,其中的enrolAdmin.js和registerUser.js实现了基于Fabric CA的注册登记。
为了让整个过程展示的更清晰,我们调整了代码。同时我们也会查看Fabric CA的数据库,以便更好的理解在登记和注册时Fabric CA的运行机制。
相关教程推荐:
1、安装
我们需要一个Fabric节点来运行Fabric CA的演示,它应当包含Hyperledger Fabric相关的所有软件。如果你还没有Fabric节点,可以参考这篇文章创建一个。
一旦准备好了Fabric节点,可以运行如下命令启动Fabcar演示:
1cd fabric-samples/fabcar 2./startFabric.sh
这个脚本会启动First网络,以及每个机构的CA。让我们先重点关注Org1的Fabric-CA。
我们使用Fabcar应用中的JavaScript代码,特别是enrollAdmin.js和registerUser.js,因为这两部分代码都是用SDK来访问Fabric CA和Fabric网络。
这就是First网络以及客户端应用与Fabric网络交互的示意。让我们再次关注ca_peerOrg1以及进行登记注册的代码。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4KpAnkV-1576464749073)(fabric-ca-exploring/pic-1.png)]](https://img-blog.csdnimg.cn/20191216105345942.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
2、Fabric CA注册登记代码
访问Fabric CA涉及到两个流程。登记(enrollment)指的是用户从指定CA请求并获取数字证书,注册(registration)通常由注册员完成,他负责告诉CA签发数字证书。
给用户签发数字证书有几种不同的方式。Fabcar脚本所采用的流程类似下面这样:
- 在Fabric CA中登记管理员,然后管理员收到签名私钥和证书,这些资料存放在 wallet/admin目录下
- 管理员在Fabric CA中注册user1,CA返回一个密文
- CA返回的密文用于在Fabric CA中登记user1,登记后得到user1的签名私钥和证书。这些资料存放在wallet/user1目录下,将被用于后续执行链码交互(查询、交易)。
enrollAdmin.js执行步骤1,registerUser.js执行步骤2和3:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RlMLyHJm-1576464749073)(fabric-ca-exploring/pic-2.png)]](https://img-blog.csdnimg.cn/20191216105404668.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
3、修改Fabric CA示例代码
我们没有修改enrollAdmin.js,它只是简单地使用默认地管理员信息(admin:adminpw),这些信息预置在fabric-samples/first-network/目录下的docker-compose-ca.yaml。结果就是admin的签名私钥和证书,保存在wallet/admin目录。
regsiterUser.js被拆分为两个文件:regUser.js和enrollUser.js,这么做的原因在于:
- 我们可以观察到Fabric CA用户注册和登记的差异之处。
- 我们可以看到这两个步骤实际上是由不同的角色执行的:注册步骤 是由注册员(admin)操作,而登记步骤则是用户自己使用得到的密文 来完成,这很重要,因为只有用户自己才可以知道密钥,管理员也不应当知道。
- 我们可以把代码中的硬编码部分抽出来作为参数,这可以让代码适应Fabric CA的其他应用场景。
下面是重写代码后的示意:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-83OTv89T-1576464749074)(fabric-ca-exploring/pic-3.png)]](https://img-blog.csdnimg.cn/20191216105423943.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
4、Fabric CA用户注册:regUser.js
regUser.js需要一个参数:登记ID,返回结果是一个密文,稍后该密文将用于用户登记。注意regUser.js的执行需要Fabric CA中存在admin钱包。
node regUser.js <enrollmentID>
代码大部分拷贝自原来的registerUser.js:
1/* 2 * SPDX-License-Identifier: Apache-2.0 3 */ 4 5'use strict'; 6 7const { FileSystemWallet, Gateway, X509WalletMixin } = require('fabric-network'); 8const path = require('path'); 9 10const ccpPath = path.resolve(__dirname, '..', '..', 'first-network', 'connection-org1.json'); 11 12async function main() { 13 try { 14 15 // Create a new file system based wallet for managing identities. 16 const walletPath = path.join(process.cwd(), 'wallet'); 17 const wallet = new FileSystemWallet(walletPath); 18 console.log(`Wallet path: ${walletPath}`); 19 20 const user = process.argv[2]; 21 22 // Check to see if we've already enrolled the user. 23 const userExists = await wallet.exists(user); 24 if (userExists) { 25 console.log('An identity for the user ' + user + ' already exists in the wallet'); 26 return; 27 } 28 29 // Check to see if we've already enrolled the admin user. 30 const adminExists = await wallet.exists('admin'); 31 if (!adminExists) { 32 console.log('An identity for the admin user "admin" does not exist in the wallet'); 33 console.log('Run the enrollAdmin.js application before retrying'); 34 return; 35 } 36 37 // Create a new gateway for connecting to our peer node. 38 const gateway = new Gateway(); 39 await gateway.connect(ccpPath, { wallet, identity: 'admin', discovery: { enabled: true, asLocalhost: true } }); 40 41 // Get the CA client object from the gateway for interacting with the CA. 42 const ca = gateway.getClient().getCertificateAuthority(); 43 const adminIdentity = gateway.getCurrentIdentity(); 44 45 // Register the user, enroll the user, and import the new identity into the wallet. 46 const secret = await ca.register({ affiliation: 'org1.department1', enrollmentID: user, role: 'client' }, adminIdentity); 47 console.log('Successfully registered user ' + user + ' and the secret is ' + secret ); 48 49 } catch (error) { 50 console.error(`Failed to register user ${user}: ${error}`); 51 process.exit(1); 52 } 53} 54 55main();
5、Fabric CA登记用户:enrollUser.js
enrollUser.js需要两个参数,登记ID和注册时得到的密文,返回的结果是在wallet目录中创建的钱包。注意enrollUser.js的运行不需要Fabric CA中admin钱包的存在。该文件应当由用户自己执行。
node enrollUser.js <enrollmentID> <secret>
代码大部分来自原始的enrollAdmin.js:
1/* 2 * SPDX-License-Identifier: Apache-2.0 3 */ 4 5'use strict'; 6 7const FabricCAServices = require('fabric-ca-client'); 8const { FileSystemWallet, X509WalletMixin } = require('fabric-network'); 9const fs = require('fs'); 10const path = require('path'); 11 12const ccpPath = path.resolve(__dirname, '..', '..', 'first-network', 'connection-org1.json'); 13const ccpJSON = fs.readFileSync(ccpPath, 'utf8'); 14const ccp = JSON.parse(ccpJSON); 15 16async function main() { 17 try { 18 19 // Create a new CA client for interacting with the CA. 20 const caInfo = ccp.certificateAuthorities['ca.org1.example.com']; 21 const caTLSCACerts = caInfo.tlsCACerts.pem; 22 const ca = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName); 23 24 // Create a new file system based wallet for managing identities. 25 const walletPath = path.join(process.cwd(), 'wallet'); 26 const wallet = new FileSystemWallet(walletPath); 27 console.log(`Wallet path: ${walletPath}`); 28 29 const user = process.argv[2]; 30 const secret = process.argv[3]; 31 32 // Check to see if we've already enrolled the admin user. 33 const userExists = await wallet.exists(user); 34 if (userExists) { 35 console.log('An identity for this user already exists in the wallet'); 36 return; 37 } 38 39 // Enroll the admin user, and import the new identity into the wallet. 40 const enrollment = await ca.enroll({ enrollmentID: user, enrollmentSecret: secret }); 41 const identity = X509WalletMixin.createIdentity('Org1MSP', enrollment.certificate, enrollment.key.toBytes()); 42 await wallet.import(user, identity); 43 console.log(`Successfully enrolled user ${user} and imported it into the wallet`); 44 45 } catch (error) { 46 console.error(`Failed to enroll admin user "admin": ${error}`); 47 process.exit(1); 48 } 49} 50 51main();
6、演示
现在我们看一下如何使用这三个脚本来为Fabcar应用在Fabric CA中注册登记user1用户。
第一步,运行fabcar/startFabric.sh
在运行前确保Fabric CA的钱包目录是空的。
1cd fabric-samples/fabcar 2./startFabric.shcd javascript 3rm -rf wallet
结果如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gLwjuvRQ-1576464749074)(fabric-ca-exploring/clear-wallet.png)]](https://img-blog.csdnimg.cn/20191216105454498.png)
第二步,安装依赖模块。
npm install
第三步,为org1的Fabric CA安装sqlite3
因为我们要查看Fabric CA的数据库,所有安装sqlite3。
打开另一个终端:
docker exec -it ca_peerOrg1 bash
为 ca_peerOrg1安装sqlite3:
1apt-get update 2apt-get install sqlite3
Fabric CA的数据库路径为:/etc/hyperledger/fabric-ca-server/fabric-ca-server.db,现在我们可以查看一下数据库:
1cd /etc/hyperledger/fabric-ca-server 2sqlite3 fabric-ca-server.db
现在已经进入了sqlite3的命令行:
sqlite> .tables
结果如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jBx8htwd-1576464749075)(fabric-ca-exploring/inspect-db.png)]](https://img-blog.csdnimg.cn/20191216105505981.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
我们的兴趣在于Fabric CA的users表和certificates表,用SQL语句查看其内容:
1sqlite> select * from users; 2sqlite> select * from certificates;
结果如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xa3RtqhT-1576464749075)(fabric-ca-exploring/table-data.png)]](https://img-blog.csdnimg.cn/20191216105513119.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
我们看到用户admin已经在数据库里。这是Fabric CA启动时生成的,这个admin几乎有所有的角色,但目前还没有生成证书。
现在我们可以开始第一个登记了:登记admin。
第四步,在Fabric CA中登记admin
首先登记admin来获得其签名私钥和证书,结果存放在wallet/admin:
node enrollAdmin.js
结果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c9GPeExj-1576464749076)(fabric-ca-exploring/pic-4.png)]](https://img-blog.csdnimg.cn/20191216105532609.png)
现在再看一下users表:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oM79SQOA-1576464749077)(fabric-ca-exploring/pic-5.png)]](https://img-blog.csdnimg.cn/20191216105526587.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
可以看到admin的某个字段从0变成了1,这是其状态字段,表示已经签发了证书。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-06MqBL2S-1576464749079)(fabric-ca-exploring/pic-6.png)]](https://img-blog.csdnimg.cn/20191216105536914.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
如果我们快速将其与Fabric CA钱包目录wallet/admin中的文件对比,就会看到admin的真实证书:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6bjo9pX1-1576464749080)(fabric-ca-exploring/pic-7.png)]](https://img-blog.csdnimg.cn/20191216105552257.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
现在在Fabric CA中注册user1:
node regUser.js user1
结果如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U2DG79NI-1576464749081)(fabric-ca-exploring/pic-8.png)]](https://img-blog.csdnimg.cn/20191216105559884.png)
我们现在收到密文MDfRiAUccsna,在用户登记时需要这个密文。在Fabric CA的钱包目录,我们还没有看到user1的钱包。
这时查看Fabric CA数据库就可以清晰地看到发生的事情。我们看到users1被添加到users表中,但是其证书还未签发。user1的属性与regUser.js的信息一致。另外,user1的状态是0,表示其证书还未签发。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eF101A3B-1576464749081)(fabric-ca-exploring/pic-9.png)]](https://img-blog.csdnimg.cn/20191216105608148.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
第五步,在Fabric CA中登记user1,获取私钥和证书
运行enrollUser.js来登记user1:
node enrollUser.js user1 MDfRiAUccsna
结果如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-11lix9gi-1576464749082)(fabric-ca-exploring/pic-10.png)]](https://img-blog.csdnimg.cn/20191216105621585.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
我们看到user1现在出现在Fabri CA的钱包里了。我们也看到在Fabric CA数据库中user1的证书已创建:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wkfedXDU-1576464749082)(fabric-ca-exploring/pic-11.png)]](https://img-blog.csdnimg.cn/20191216105628956.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
状态从0迁移到1,表示证书已签发:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7LTbwn30-1576464749083)(fabric-ca-exploring/pic-12.png)]](https://img-blog.csdnimg.cn/20191216105644792.png)
第六步,用user1运行查询脚本,检查是否有权限
node query.js
结果如下:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2YIBfTsc-1576464749083)(fabric-ca-exploring/pic-13.png)]](https://img-blog.csdnimg.cn/20191216105652468.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NoZWJhbzMzMzM=,size_16,color_FFFFFF,t_70)
原文链接:Faric CA教程 - 汇智网