⭐ 하이퍼레저 패브릭 2.2 ver 기준

‘디앱’ 은 블록체인 네트워크에 있는 특정 체인코드의 특정 기능을 요청해서 실행하면 결과를 받는것이 디앱의 목적이다

  1. 디앱은 요청하기 전에 디앱은 ‘인증서’ 를 가지고 있어야한다 👉 그래야 로그인을 할수있다

  2. 디앱은 ‘CA (Certificate Authority)’ 에 인증서를 요청해서 인증서를 받아와야한다

  3. ‘CA’에 접속할 수 있는 주소를 가지고 있어야하는데

  4. 블록체인 네트워크를 실행 시키면 peer / orderer / CA 까지 같이 켜진다

  5. 네트워크를 키면 주소가 결정되는데 이때 다같이 생성된 peer / orderer / CA 주소를 모아서 ‘cpp’ json 파일을 만든다 ⭐ (ccp = abi 와 비슷함)

  6. 디앱은 ‘ccp’ 를 읽어와서 ‘CA’ 에 접속할수있다 (주소를 아니까)

  7. ‘CA’ 에 접속을 해서 인증서를 받아오고

  8. 받아온 인증서는 지갑(Wallet) 에 저장한다

  9. 디앱은 인증서를 꺼내서 ‘인증’을 함과 동시에 / 체인코드를 요청하고 결과를 받는다

준비물 생성 👉 네트워크 구동 👉 채널 조인 👉 앵커피어 설정 👉 체인코드 설치 & 배포


Register & Enroll

관리자의 입장으로서 유저를 등록 👉 Register
‘CA’ 에 관리자 계정을 등록하는 행위를 ‘Register’ 라고 한다

유저의 입장으로는 발급 👉 enroll
등록되어있는 사용자 인증서를 발급 받아오는 행위를 ‘Enroll’ 이라고 한다

  • enrollAdmin 👉 관리자 지갑 생성 👉 인증서받기

  • registerUser 👉 사용자 지갑 생성 👉 인증서받기

  • 관리자가 사용자를 등록시킬때 관리자 인증서를 확인

  • 관리자가 본인의 권한으로 사용자를 등록해줘야 사용자가 인증서를 발급받을수있다

  • 유저 등록을 위해서는 관리자(Admin) 권한이 필요하다

  • 관리자의 권한으로 ‘CA’ 에 등록 👉 사용자 인증서 발급

네트워크 동작 👉 네트워크에 맞는 CCP 생성 👉 CCP를 이용하여 CA 접속 👉 필요한 인증서 발급 👉 wallet에 저장 & 꺼내쓰기

⭐ 실제 서비스에서는 회원가입, 핸드폰 인증 등 같은 과정을 거쳐서 인증서를 발급 (Enroll)

예를들어

회사(CA)에 처음 입사했을때 회사 DB에 넣을
나의 개인정보를 최초로 등록하는 과정 👉 Register

회사(CA)에 내가 출입카드를 발급요청하면 출입카드를 준다
회사 DB에는 나의 정보가 등록되어있을 것이다
👉 등록되어있는 DB를 기준으로 출입카드를 발급해준다 (Enroll)
출입카드를 분실했어도 DB를 기준으로 재발급이 가능하다


enrollAdmin 코드

  1. ‘ccp’ 에 접근해서 CA 주소를 찾는 작업
  2. 지갑 유무 확인 체크 (관리자 권한 체크)
  3. 관리자 권한으로 인증서 발급 후 지갑에 저장
"use strict";

const FabricCAServices = require("fabric-ca-client");
const { Wallets } = require("fabric-network");
const fs = require("fs");
const path = require("path");

async function main() {
  try {
    const ccpPath = path.resolve(__dirname, "ccp", "connection-org1.json");
    // ccp 파일 json 에 접근 👉 접속할 주소를 찾아야함
    const ccp = JSON.parse(fs.readFileSync(ccpPath, "utf8"));
    // json을 parse 시킨다

    const caInfo = ccp.certificateAuthorities["ca.org1.example.com"];
    // json 파일에서 접속할 url 주소를 찾음
    const caTLSCACerts = caInfo.tlsCACerts.pem;
    // 찾은 url CA 주소
    const ca = new FabricCAServices(
      caInfo.url,
      { trustedRoots: caTLSCACerts, verify: false },
      caInfo.caName
    );

    const walletPath = path.join(process.cwd(), "wallet");
    // wallet 열기 / 없으면 생성 / 현재경로에
    const wallet = await Wallets.newFileSystemWallet(walletPath);
    console.log(`Wallet path: ${walletPath}`);

    const identity = await wallet.get("admin");
    // admin 이라는 인증서가 있는지 확인
    if (identity) {
      console.log(
        'An identity for the admin user "admin" already exists in the wallet'
      );
      return;
    }

    // ⭐ CA가 켜질때 admin 하나는 register 된 상태로 켜진다
    // 최초의 관리자
    const enrollment = await ca.enroll({
      enrollmentID: "admin", // 최초 이미 등록되어있는 관리자 아이디
      enrollmentSecret: "adminpw", // 관리자 비밀번호
    });
    const x509Identity = {
      credentials: {
        certificate: enrollment.certificate, // 관리자권한으로 발급
        privateKey: enrollment.key.toBytes(), // 관리자권한으로 발급
      },
      mspId: "Org1MSP",
      type: "X.509",
    };
    await wallet.put("admin", x509Identity);
    // 지갑에 관리자 인증서가 한개 발급되어 저장(put)
    console.log(
      'Successfully enrolled admin user "admin" and imported it into the wallet'
    );
  } catch (error) {
    console.error(`Failed to enroll admin user "admin": ${error}`);
    process.exit(1);
  }
}

main();

registerUser 코드

  1. ‘ccp’ 에 접근해서 CA 주소를 찾는 작업
  2. 지갑 유무 확인 체크 (관리자 권한 체크)
  3. 관리자의 권한으로 유저를 등록
"use strict";

const { Wallets } = require("fabric-network");
const FabricCAServices = require("fabric-ca-client");
const fs = require("fs");
const path = require("path");

async function main() {
  try {
    const ccpPath = path.resolve(__dirname, "ccp", "connection-org1.json"); // ccp 파일 json 에 접근 👉 접속할 주소를 찾아야함
    const ccp = JSON.parse(fs.readFileSync(ccpPath, "utf8"));
    // json을 parse 시킨다

    const caURL = ccp.certificateAuthorities["ca.org1.example.com"].url;
    // json 파일에서 접속할 url 주소를 찾음
    const ca = new FabricCAServices(caURL); // 찾은 url CA 주소

    const walletPath = path.join(process.cwd(), "wallet");
    const wallet = await Wallets.newFileSystemWallet(walletPath);
    console.log(`Wallet path: ${walletPath}`);

    const userIdentity = await wallet.get("appUser");
    if (userIdentity) {
      console.log(
        'An identity for the user "appUser" already exists in the wallet'
      );
      return;
    }

    const adminIdentity = await wallet.get("admin");
    // admin(관리자) 권한 불러오기
    if (!adminIdentity) {
      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;
    }

    const provider = wallet
      .getProviderRegistry()
      .getProvider(adminIdentity.type);
    const adminUser = await provider.getUserContext(adminIdentity, "admin"); // 관리자권한 생성

    const secret = await ca.register(
      {
        affiliation: "org1.department1", // 소속
        enrollmentID: "appUser", // 아이디
        role: "client", // 역할(권한)
      }, // admin / peer / client 3개중 하나
      adminUser // 관리자 권한으로 User 등록
    );
    //------------ admin (관리자)의 역할 끝
    //------------ dapp 에서 조작해야할 영역 👇👇
    const enrollment = await ca.enroll({
      enrollmentID: "appUser",
      enrollmentSecret: secret,
    });
    const x509Identity = {
      credentials: {
        certificate: enrollment.certificate,
        privateKey: enrollment.key.toBytes(),
      },
      mspId: "Org1MSP",
      type: "X.509",
    };
    await wallet.put("appUser", x509Identity);
    console.log(
      'Successfully registered and enrolled admin user "appUser" and imported it into the wallet'
    );
  } catch (error) {
    console.error(`Failed to register user "appUser": ${error}`);
    process.exit(1);
  }
}

main();