总览
Hyperledger Fabric是一个许可的区块链平台。必须先识别并获得许可,然后才能与光纤网络交互。身份是通过数字证书实现的,因此需要证书颁发机构(CA)来处理证书管理。
虽然Hyperledger Fabric允许使用Enterprise世界中可能需要的第三方CA,但它还附带了方便的Fabric-CA,可作为Fabric网络的CA。由于Fabric示例中的大多数应用示例都使用Fabric-CA(使用Basic Network和First Network),因此我们将研究Fabric-CA,尤其是其在用户注册和注册中的作用。
在本文中,我们使用部署在First Network上的Fabcar应用程序。此示例应用程序包含使用软件开发套件(SDK)的链码和客户端应用程序。特别是两个代码enrollAdmin.js和registerUser.js已在Fabric-CA上实现了注册和注册。
为了使过程更容易证明,我对代码进行了重新整理,以使事情更清楚。同时,我们将查看Fabric-CA数据库,以更好地了解在注册和用户注册过程中Fabric-CA方面发生的情况。
设定
我们需要一个Fabric节点来进行演示。它具有所有必备软件以及与Hyperledger Fabric相关的软件。如果还没有这样的结构节点,可以参考本文创建一个。
[##
设置Hyperledger Fabric主机并创建机器映像
使用机器映像(例如AMI)来加快Hyperledger Fabric主机的准备,以进行测试和练习
一旦有了该节点,就可以运行fabric-samples/fabcar/startFabric.sh脚本以启动Fabcar。
cd fabric-samples/fabcar
./startFabric.sh
该脚本建立了第一个网络,并为每个组织建立了CA。我还有另一篇文章介绍Fabcar的细节。在这项工作中,我们的重点是针对Org1的Fabric-CA。
我们正在使用Fabcar应用程序中提供的Javascript代码。特别是,我们研究了enrollAdmin.js和registerUser.js。因为两者都使用SDK与Fabric-CA和Fabric网络进行交互。
这是第一网络的外观,以及给定的客户端应用程序代码与光纤网络的交互方式。再次,我们将重点关注ca_peerOrg1以及本文中用于注册和注册的两个代码(enrollAdmin.js和registerUser.js)。

登记和注册代码
报名和注册
这是我们与Fabric-CA交互的两个过程。注册是用户请求并从给定CA获得数字证书的过程。注册通常由注册服务商完成,告诉注册管理机构颁发数字证书。
有多种方法可以向用户颁发数字证书。为了我们的利益并基于Fabcar脚本,过程如下所示
- 一个管理员(登记处)被登记到CA. 随后,管理员收到关于该签名密钥和证书管理。它们存储在wallet / admin目录中。
- 然后,管理员使用适当的信息将user1注册到CA中。CA返回一个秘密。
- 然后,使用此机密将user1注册到CA。结果是user1的签名密钥和证书。它们存储在wallet / user1目录中,以后将用于执行链码交互(查询和调用)。
脚本enrollAdmin.js执行步骤1,而registerUser.js执行步骤2和3。

重做代码
该enrollAdmin.js保持不变。它仅使用默认的引导程序管理员(admin:adminpw),该默认值已在docker-compose-ca.yamlinside中预设fabric-samples/first-network/。结果是该管理员(注册商)的签名密钥和证书保存在wallet/admin目录中。
为了更好地说明,registerUser.js分为两个:regUser.js和enrollUser.js。背后的原因
- 我们可以观察到用户注册和注册之间的区别。
- 我们可以证明实际上这两个步骤应该由不同的一方完成:注册由注册服务商(admin)完成,而用户的注册由用户使用给出的机密完成。这很重要,因为只有除用户以外的任何人都不能接收签名密钥,即使注册服务商不知道该签名也应保密。
- 我们可以取出代码中的硬编码部分(例如user1),并将其作为参数。这使代码在其他情况下更易于使用。
这是重写代码后的样子。

注册用户:regUser.js
regUser.js需要一个参数,即注册ID。结果是一个秘密,稍后将用于用户注册。请注意,*** regUser.js***需要存在管理员钱包。
node regUser.js <enrollmentID>
经过适当的修改,代码大部分是从原始的registerUser.js复制而来。
/*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const { FileSystemWallet, Gateway, X509WalletMixin } = require('fabric-network');
const path = require('path');
const ccpPath = path.resolve(__dirname, '..', '..', 'first-network', 'connection-org1.json');
async function main() {
try {
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
const user = process.argv[2];
// Check to see if we've already enrolled the user.
const userExists = await wallet.exists(user);
if (userExists) {
console.log('An identity for the user ' + user + ' already exists in the wallet');
return;
}
// Check to see if we've already enrolled the admin user.
const adminExists = await wallet.exists('admin');
if (!adminExists) {
console.log('An identity for the admin user "admin" does not exist in the wallet');
console.log('Run the enrollAdmin.js application before retrying');
return;
}
// Create a new gateway for connecting to our peer node.
const gateway = new Gateway();
await gateway.connect(ccpPath, { wallet, identity: 'admin', discovery: { enabled: true, asLocalhost: true } });
// Get the CA client object from the gateway for interacting with the CA.
const ca = gateway.getClient().getCertificateAuthority();
const adminIdentity = gateway.getCurrentIdentity();
// Register the user, enroll the user, and import the new identity into the wallet.
const secret = await ca.register({ affiliation: 'org1.department1', enrollmentID: user, role: 'client' }, adminIdentity);
console.log('Successfully registered user ' + user + ' and the secret is ' + secret );
} catch (error) {
console.error(`Failed to register user ${user}: ${error}`);
process.exit(1);
}
}
main();
注册用户:enrollUser.js
enrollUser.js需要两个参数,即注册ID和注册时获得的机密。结果是在wallet目录中的指定目录中创建了一个钱包。请注意,*** enrollUser.js***不需要管理钱包。它应该由用户自己执行。
node enrollUser.js <enrollmentID> <secret>
该代码引用了经过适当修改的原始enrollAdmin.js。
/*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const FabricCAServices = require('fabric-ca-client');
const { FileSystemWallet, X509WalletMixin } = require('fabric-network');
const fs = require('fs');
const path = require('path');
const ccpPath = path.resolve(__dirname, '..', '..', 'first-network', 'connection-org1.json');
const ccpJSON = fs.readFileSync(ccpPath, 'utf8');
const ccp = JSON.parse(ccpJSON);
async function main() {
try {
// Create a new CA client for interacting with the CA.
const caInfo = ccp.certificateAuthorities['ca.org1.example.com'];
const caTLSCACerts = caInfo.tlsCACerts.pem;
const ca = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName);
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
const user = process.argv[2];
const secret = process.argv[3];
// Check to see if we've already enrolled the admin user.
const userExists = await wallet.exists(user);
if (userExists) {
console.log('An identity for this user already exists in the wallet');
return;
}
// Enroll the admin user, and import the new identity into the wallet.
const enrollment = await ca.enroll({ enrollmentID: user, enrollmentSecret: secret });
const identity = X509WalletMixin.createIdentity('Org1MSP', enrollment.certificate, enrollment.key.toBytes());
await wallet.import(user, identity);
console.log(`Successfully enrolled user ${user} and imported it into the wallet`);
} catch (error) {
console.error(`Failed to enroll admin user "admin": ${error}`);
process.exit(1);
}
}
main();
示范
我们将展示如何运行这三个脚本来为Fabcar应用程序注册和注册user1。
第1步:运行fabcar/startFabric.sh并确保钱包为空。
cd fabric-samples/fabcar
./startFabric.sh
cd javascript
rm -rf wallet

步骤2:安装所需的模块
npm install
步骤3:在org1的CA中安装sqlite3
当我们要检查CA中的数据库时,请安装sqlite3以执行检查。
打开另一个终端。
docker exec -it ca_peerOrg1 bash
在ca_peerOrg1中安装sqlite3。
apt-get update
apt-get install sqlite3
Fabric-CA数据库保存在中/etc/hyperledger/fabric-ca-server/fabric-ca-server.db。现在我们可以检查数据库了。
cd /etc/hyperledger/fabric-ca-server
sqlite3 fabric-ca-server.db
现在我们在sqlite的命令行外壳中。
sqlite> .tables

在这些表中,我们对users表和certificates表感兴趣。要查看这些表中的内容。
sqlite> select * from users;
sqlite> select * from certificates;

我们看到数据库中已经有一个用户admin。这是在启动CA时完成的(请使用-b admin:adminpw参阅docker-compose文件中的命令)。而且这个引导管理员几乎设置了所有角色。尚未生成证书(尚未完成注册)。
现在,我们准备执行第一次注册:使用此admin的registrar的注册。
步骤4:注册管理员(注册商)
我们首先注册管理员,以获取存储在中的管理员的签名密钥和证书wallet/admin。
node enrollAdmin.js

如果现在再次检查CA中的users表。

我们可以看到admin中的字段从0更改为1。这是state,表示已颁发证书。现在我们可以看到已颁发证书。

如果快速将其与存储的内容进行比较wallet/admin,我们将看到这是admin的实际证书。

步骤5:将user1注册到CA
现在,我们运行regUser.js将user1注册到CA中。
node regUser.js user1

现在,我们收到了秘密MDfRiAUccsna。在下一步的用户注册中需要这样做。我们还没有找到user1的新钱包。
如果我们检查CA数据库,将会更清楚地了解发生了什么。我们看到user1已添加到users表,而user1尚未创建新证书(尚未注册)。user1的属性与regUser.js中编码的内容匹配。同样,user1的状态为0 ,这意味着尚未颁发证书。

步骤5:注册user1并获取签名密钥和证书
运行enrollUser.js以使用密码将user1注册到CA。
node enrollUser.js user1 MDfRiAUccsna

我们看到user1现在在钱包里。我们还在CA数据库中看到为user1创建的新证书。

颁发证书后(注册了user1之后)状态更改为1 。

步骤6:最后,我们可以使用user1运行Fabcar脚本(query.js),并查看user1是否可以执行查询。请注意,在query.js中, user1是硬编码的。
node query.js

用户user1可以按预期执行链码查询。
奖励:模拟丢失user1钱包
让我们删除user1钱包以模拟损失。
rm -r wallet/user1

我们首先将尝试使用相同的秘密再次注册user1。
node enrollUser.js user1 MDfRiAUccsna

注册失败。如果我们查看CA的日志,我们就会知道为什么会这样。
docker logs ca_peerOrg1

现在,我们在Fabric-CA数据库上做一个技巧。首先,在证书表中删除user1,然后在users表中将user1的状态从1 更改为0 。
sqlite> delete from certificates where id='user1';
sqlite> update users set state=0 where id='user1';

完成此技巧后,我们可以使用相同的密码再次注册user1。

此新的user1钱包可再次用于链码查询。
注意:这不是正式的方式,因为我们应该避免直接修改数据库。但是,如果需要的话,这可以是一种方法。
步骤7:清理
退出CA容器
sqlite> .exit
# exit
清理Fabcar和First-Network
cd fabric-samples/first-network
./byfn.sh down
docker rm $(docker ps -aq)
docker rmi $(docker images dev-* -q)
摘要
本文重点介绍Fabric-CA,说明如何使用SDK进行注册和注册。重新编写代码后,我们将逐步了解该过程。通过研究存储在Fabric-CA数据库中的信息,我们了解了Fabric-CA如何处理用户注册和注册。我们还执行了一个小技巧,以防钱包丢失时为用户重新签发签名密钥和证书。