探索Fabric-CA的登記和注冊(cè)

總覽

Hyperledger Fabric是一個(gè)許可的區(qū)塊鏈平臺(tái)。必須先識(shí)別并獲得許可,然后才能與光纖網(wǎng)絡(luò)交互。身份是通過數(shù)字證書實(shí)現(xiàn)的,因此需要證書頒發(fā)機(jī)構(gòu)(CA)來處理證書管理。

雖然Hyperledger Fabric允許使用Enterprise世界中可能需要的第三方CA,但它還附帶了方便的Fabric-CA,可作為Fabric網(wǎng)絡(luò)的CA。由于Fabric示例中的大多數(shù)應(yīng)用示例都使用Fabric-CA(使用Basic Network和First Network),因此我們將研究Fabric-CA,尤其是其在用戶注冊(cè)和注冊(cè)中的作用。

在本文中,我們使用部署在First Network上的Fabcar應(yīng)用程序。此示例應(yīng)用程序包含使用軟件開發(fā)套件(SDK)的鏈碼和客戶端應(yīng)用程序。特別是兩個(gè)代碼enrollAdmin.jsregisterUser.js已在Fabric-CA上實(shí)現(xiàn)了注冊(cè)和注冊(cè)。

為了使過程更容易證明,我對(duì)代碼進(jìn)行了重新整理,以使事情更清楚。同時(shí),我們將查看Fabric-CA數(shù)據(jù)庫(kù),以更好地了解在注冊(cè)和用戶注冊(cè)過程中Fabric-CA方面發(fā)生的情況。

設(shè)定

我們需要一個(gè)Fabric節(jié)點(diǎn)來進(jìn)行演示。它具有所有必備軟件以及與Hyperledger Fabric相關(guān)的軟件。如果還沒有這樣的結(jié)構(gòu)節(jié)點(diǎn),可以參考本文創(chuàng)建一個(gè)。

[##

設(shè)置Hyperledger Fabric主機(jī)并創(chuàng)建機(jī)器映像

使用機(jī)器映像(例如AMI)來加快Hyperledger Fabric主機(jī)的準(zhǔn)備,以進(jìn)行測(cè)試和練習(xí)

一旦有了該節(jié)點(diǎn),就可以運(yùn)行fabric-samples/fabcar/startFabric.sh腳本以啟動(dòng)Fabcar。

cd fabric-samples/fabcar
./startFabric.sh

該腳本建立了第一個(gè)網(wǎng)絡(luò),并為每個(gè)組織建立了CA。我還有另一篇文章介紹Fabcar的細(xì)節(jié)。在這項(xiàng)工作中,我們的重點(diǎn)是針對(duì)Org1的Fabric-CA。

我們正在使用Fabcar應(yīng)用程序中提供的Javascript代碼。特別是,我們研究了enrollAdmin.jsregisterUser.js。因?yàn)閮烧叨际褂肧DK與Fabric-CA和Fabric網(wǎng)絡(luò)進(jìn)行交互。

這是第一網(wǎng)絡(luò)的外觀,以及給定的客戶端應(yīng)用程序代碼與光纖網(wǎng)??絡(luò)的交互方式。再次,我們將重點(diǎn)關(guān)注ca_peerOrg1以及本文中用于注冊(cè)和注冊(cè)的兩個(gè)代碼(enrollAdmin.jsregisterUser.js)。

Fabcar部署在First Network中,客戶端應(yīng)用程序使用SDK訪問Fabric網(wǎng)絡(luò)。

登記和注冊(cè)代碼

報(bào)名和注冊(cè)

這是我們與Fabric-CA交互的兩個(gè)過程。注冊(cè)是用戶請(qǐng)求并從給定CA獲得數(shù)字證書的過程。注冊(cè)通常由注冊(cè)服務(wù)商完成,告訴注冊(cè)管理機(jī)構(gòu)頒發(fā)數(shù)字證書。

有多種方法可以向用戶頒發(fā)數(shù)字證書。為了我們的利益并基于Fabcar腳本,過程如下所示

  1. 一個(gè)管理員(登記處)被登記到CA. 隨后,管理員收到關(guān)于該簽名密鑰和證書管理。它們存儲(chǔ)在wallet / admin目錄中。
  2. 然后,管理員使用適當(dāng)?shù)男畔?strong>user1注冊(cè)到CA中。CA返回一個(gè)秘密
  3. 然后,使用此機(jī)密將user1注冊(cè)到CA。結(jié)果是user1的簽名密鑰和證書。它們存儲(chǔ)在wallet / user1目錄中,以后將用于執(zhí)行鏈碼交互(查詢和調(diào)用)。

腳本enrollAdmin.js執(zhí)行步驟1,而registerUser.js執(zhí)行步驟2和3。

fabcar應(yīng)用程序中提供的代碼

重做代碼

enrollAdmin.js保持不變。它僅使用默認(rèn)的引導(dǎo)程序管理員(admin:adminpw),該默認(rèn)值已在docker-compose-ca.yamlinside中預(yù)設(shè)fabric-samples/first-network/。結(jié)果是該管理員(注冊(cè)商)的簽名密鑰和證書保存在wallet/admin目錄中。

為了更好地說明,registerUser.js分為兩個(gè):regUser.jsenrollUser.js。背后的原因

  • 我們可以觀察到用戶注冊(cè)和注冊(cè)之間的區(qū)別。
  • 我們可以證明實(shí)際上這兩個(gè)步驟應(yīng)該由不同的一方完成:注冊(cè)由注冊(cè)服務(wù)商(admin)完成,而用戶的注冊(cè)由用戶使用給出的機(jī)密完成。這很重要,因?yàn)橹挥谐脩粢酝獾娜魏稳硕疾荒芙邮蘸灻荑€,即使注冊(cè)服務(wù)商不知道該簽名也應(yīng)保密。
  • 我們可以取出代碼中的硬編碼部分(例如user1),并將其作為參數(shù)。這使代碼在其他情況下更易于使用。

這是重寫代碼后的樣子。

重寫代碼以更清晰地顯示三個(gè)步驟

注冊(cè)用戶:regUser.js

regUser.js需要一個(gè)參數(shù),即注冊(cè)ID。結(jié)果是一個(gè)秘密,稍后將用于用戶注冊(cè)。請(qǐng)注意,*** regUser.js***需要存在管理員錢包。

node regUser.js <enrollmentID>

經(jīng)過適當(dāng)?shù)男薷?,代碼大部分是從原始的registerUser.js復(fù)制而來。

/*
 * 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();

注冊(cè)用戶:enrollUser.js

enrollUser.js需要兩個(gè)參數(shù),即注冊(cè)ID和注冊(cè)時(shí)獲得的機(jī)密。結(jié)果是在wallet目錄中的指定目錄中創(chuàng)建了一個(gè)錢包。請(qǐng)注意,*** enrollUser.js***不需要管理錢包。它應(yīng)該由用戶自己執(zhí)行。

node enrollUser.js <enrollmentID> <secret>

該代碼引用了經(jīng)過適當(dāng)修改的原始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();

示范

我們將展示如何運(yùn)行這三個(gè)腳本來為Fabcar應(yīng)用程序注冊(cè)和注冊(cè)user1。

第1步:運(yùn)行fabcar/startFabric.sh并確保錢包為空。

cd fabric-samples/fabcar
./startFabric.sh
cd javascript
rm -rf wallet
刪除**錢包**目錄中的所有內(nèi)容

步驟2:安裝所需的模塊

npm install

步驟3:在org1的CA中安裝sqlite3

當(dāng)我們要檢查CA中的數(shù)據(jù)庫(kù)時(shí),請(qǐng)安裝sqlite3以執(zhí)行檢查。

打開另一個(gè)終端。

docker exec -it ca_peerOrg1 bash

ca_peerOrg1中安裝sqlite3。

apt-get update
apt-get install sqlite3

Fabric-CA數(shù)據(jù)庫(kù)保存在中/etc/hyperledger/fabric-ca-server/fabric-ca-server.db?,F(xiàn)在我們可以檢查數(shù)據(jù)庫(kù)了。

cd /etc/hyperledger/fabric-ca-server
sqlite3 fabric-ca-server.db

現(xiàn)在我們?cè)趕qlite的命令行外殼中。

sqlite> .tables
image.png

在這些表中,我們對(duì)users表certificates表感興趣。要查看這些表中的內(nèi)容。

sqlite> select * from users;
sqlite> select * from certificates;
image.png

我們看到數(shù)據(jù)庫(kù)中已經(jīng)有一個(gè)用戶admin。這是在啟動(dòng)CA時(shí)完成的(請(qǐng)使用-b admin:adminpw參閱docker-compose文件中的命令)。而且這個(gè)引導(dǎo)管理員幾乎設(shè)置了所有角色。尚未生成證書(尚未完成注冊(cè))。

現(xiàn)在,我們準(zhǔn)備執(zhí)行第一次注冊(cè):使用此admin的registrar的注冊(cè)。

步驟4:注冊(cè)管理員(注冊(cè)商)

我們首先注冊(cè)管理員,以獲取存儲(chǔ)在中的管理員的簽名密鑰和證書wallet/admin

node enrollAdmin.js
image.png

如果現(xiàn)在再次檢查CA中的users表。

image.png

我們可以看到admin中的字段從0更改為1。這是state,表示已頒發(fā)證書?,F(xiàn)在我們可以看到已頒發(fā)證書。

image.png

如果快速將其與存儲(chǔ)的內(nèi)容進(jìn)行比較wallet/admin,我們將看到這是admin的實(shí)際證書。

image.png

步驟5:將user1注冊(cè)到CA

現(xiàn)在,我們運(yùn)行regUser.jsuser1注冊(cè)到CA中。

node regUser.js user1
image.png

現(xiàn)在,我們收到了秘密MDfRiAUccsna。在下一步的用戶注冊(cè)中需要這樣做。我們還沒有找到user1的新錢包。

如果我們檢查CA數(shù)據(jù)庫(kù),將會(huì)更清楚地了解發(fā)生了什么。我們看到user1已添加到users表,而user1尚未創(chuàng)建新證書(尚未注冊(cè))。user1的屬性與regUser.js中編碼的內(nèi)容匹配。同樣,user1的狀態(tài)為0 ,這意味著尚未頒發(fā)證書。

image.png

步驟5:注冊(cè)user1并獲取簽名密鑰和證書

運(yùn)行enrollUser.js以使用密碼將user1注冊(cè)到CA。

node enrollUser.js user1 MDfRiAUccsna
image.png

我們看到user1現(xiàn)在在錢包里。我們還在CA數(shù)據(jù)庫(kù)中看到為user1創(chuàng)建的新證書。

image.png

頒發(fā)證書后(注冊(cè)了user1之后)狀態(tài)更改為1 。

image.png

步驟6:最后,我們可以使用user1運(yùn)行Fabcar腳本(query.js),并查看user1是否可以執(zhí)行查詢。請(qǐng)注意,在query.js中, user1是硬編碼的。

node query.js
image.png

用戶user1可以按預(yù)期執(zhí)行鏈碼查詢。

獎(jiǎng)勵(lì):模擬丟失user1錢包

讓我們刪除user1錢包以模擬損失。

rm -r wallet/user1
image.png

我們首先將嘗試使用相同的秘密再次注冊(cè)user1。

node enrollUser.js user1 MDfRiAUccsna
image.png

注冊(cè)失敗。如果我們查看CA的日志,我們就會(huì)知道為什么會(huì)這樣。

docker logs ca_peerOrg1
image.png

現(xiàn)在,我們?cè)贔abric-CA數(shù)據(jù)庫(kù)上做一個(gè)技巧。首先,在證書表中刪除user1,然后在users表中將user1的狀態(tài)從1 更改為0 。

sqlite> delete from certificates where id='user1';
sqlite> update users set state=0 where id='user1';
image.png

完成此技巧后,我們可以使用相同的密碼再次注冊(cè)user1。

image.png

此新的user1錢包可再次用于鏈碼查詢。

注意:這不是正式的方式,因?yàn)槲覀儜?yīng)該避免直接修改數(shù)據(jù)庫(kù)。但是,如果需要的話,這可以是一種方法。

步驟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)

摘要

本文重點(diǎn)介紹Fabric-CA,說明如何使用SDK進(jìn)行注冊(cè)和注冊(cè)。重新編寫代碼后,我們將逐步了解該過程。通過研究存儲(chǔ)在Fabric-CA數(shù)據(jù)庫(kù)中的信息,我們了解了Fabric-CA如何處理用戶注冊(cè)和注冊(cè)。我們還執(zhí)行了一個(gè)小技巧,以防錢包丟失時(shí)為用戶重新簽發(fā)簽名密鑰和證書。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容