Hyperledger Fabric - balance transfer (2) Registered users

Detailed analysis of the user registration (register) and login (enroll) functions of the blance transfer example.

Source code analysis

app.js1. First analyze the routing functions for user registration and login in the files in the project root directory . Note that this is tokenvery important. In subsequent requests, as long as the request header is attached token, the js routing function can directly obtain the parameters: req.usernamereq.orgName

// 注册和登录用户
app.post('/users', async function(req, res) {
    // 获取并检验参数
    var username = req.body.username;
    var orgName = req.body.orgName;
    if (!username) {
        res.json(getErrorMessage('\'username\''));
        return;
    }
    if (!orgName) {
        res.json(getErrorMessage('\'orgName\''));
        return;
    }
    // 生成token,包含信息username, orgName
    var token = jwt.sign({
        exp: Math.floor(Date.now() / 1000) + parseInt(hfc.getConfigSetting('jwt_expiretime')),
        username: username,
        orgName: orgName
    }, app.get('secret'));

    // 注册成功则返回响应信息,并附上token
    let response = await helper.getRegisteredUser(username, orgName, true);
    if (response && typeof response !== 'string') {
        response.token = token;
        res.json(response);

    // 注册失败则返回错误信息
    } else {
        res.json({success: false, message: response});
    }

});

2. Continue to enter helper.js, find the function to getRegisteredUser()analyze its specific implementation: Internally,
it should be noted that the user's login ( enroll) process is implemented inside SDKthe setUserContext()function (login admin is also), when the incoming object is not an Userobject, but a file containing usernameand passwordWhen the attribute is an object, the _setUserFromConfig()method will be called, the login operation will be performed internally, and an Userobject will be returned. The user object is then setUserContext()stored locally (persistence).
Since SDKthe property is not set when the object is created _enrollmentSecret, there is no value in the return information of the registration login and the locally stored key-value pair sectect, so you can make some modifications to the source code (not very elegant), or you can directly modify the SDKcode.

var getRegisteredUser = async function(username, userOrg, isJson) {
    try {
        // 获得一个客户端实例
        var client = await getClientForOrg(userOrg);

        // 通过SDK中的getUserContext()方法获取User对象(包含证书和私钥等信息)
        // 本质上是通过KeyValueStore接口从本地存储加载User数据
        var user = await client.getUserContext(username, true);
        // 用户存在且已经登录
        if (user && user.isEnrolled()) {
            logger.info('Successfully loaded member from persistence');
        } 
        // 用户未登录,需要使用admin来进行注册
        else {
            // 根据config.json配置文件中的信息,获得的admins结构如下:
            // admins = [{username:"admin", secret:"adminpw"}]
            var admins = hfc.getConfigSetting('admins');
            let adminUserObj = await client.setUserContext({username: admins[0].username, password: admins[0].secret});
            // 生成CA服务实现
            let caClient = client.getCertificateAuthority();
            // 通过CA服务和admin来注册该user,获得密码secret
            let secret = await caClient.register({
                enrollmentID: username,
                affiliation: userOrg.toLowerCase() + '.department1'
            }, adminUserObj);
            // enroll成功,将用户上下文信息(证书,私钥)以及密钥对持久化地很存入本地存储中
            user = await client.setUserContext({username:username, password:secret});
            // 改动:添加属性后重新存入本地存储,以保证获取secret值
            user._enrollmentSecret = secret;
            await client.setUserContext(user);
        }
        if(user && user.isEnrolled) {
            // 返回包含登录信息的json对象
            if (isJson && isJson === true) {
                var response = {
                    success: true,
                    secret: user._enrollmentSecret,
                    message: username + ' enrolled Successfully',
                };
                return response;
            }
        } else {
            throw new Error('User was not enrolled ');
        }
    } catch(error) {
        logger.error('Failed to get registered user: %s with error: %s', username, error.toString());
        return 'failed '+error.toString();
    }
};

getClientForOrg()3. Let's look at the function that generates the client :

async function getClientForOrg (userorg, username) {
    // 通过加载配置文件来创建客户端实例

    // 根据config.js文件中的配置文件路径设置可知:
    // 此步是加载 ./artifacts/network-config.yaml 网络配置文件
    // 文件中包含 需要进行交互的目标 blockchain 网络的信息
    let config = '-connection-profile-path';
    let client = hfc.loadFromConfig(hfc.getConfigSetting('network'+config));

    // 此步是加载 ./artifacts/userorg.yaml 其中userorg为org1/org2
    // 文件中包含用户状态存储路径(用户键值对)以及公私钥的存储路径(一系列密钥对)
    client.loadFromConfig(hfc.getConfigSetting(userorg+config));

    // 初始化创建状态存储和加密(密钥)存储
    await client.initCredentialStores();

    // 如果参数中含有username,则在持久存储中查找该用户,如果查到则说明该用户已经注册并登录
    // 并将该User对象分配给刚刚生成的clietn实例
    if(username) {
        let user = await client.getUserContext(username, true);
        if(!user) {
            throw new Error(util.format('User was not found :', username));
        } else {
            logger.debug('User %s was found to be registered and enrolled', username);
        }
    }

    return client;
}

test

  • run the network

    ./runApp.sh
  • After Org1registering and logging in user Jim:

    ORG1_TOKEN=$(curl -s -X POST \
      http://localhost:4000/users \
      -H "content-type: application/x-www-form-urlencoded" \
      -d "username=Jim&orgName=Org1")

    result:

    {
    "success": true,
    "secret": "ZVGfOMkmQmBH",
    "message": "Jim enrolled Successfully",
    "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MjMyODE0OTQsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Ik9yZzEiLCJpYXQiOjE1MjMyNDU0OTR9.61-rp1Nye2Rg8e-91WCQwrTAkGvSJ0Bw_Y0OHQ-hDcg"
    }

    The user's state information is stored in ./fabric-client-kv-org1, which contains the ski identifier signingIdentity(in hexadecimal bytes format) and certificate certificate(in pem format) of the user's private key. The user's public and private keys (pem format) are stored in /tmp/fabric-client-kvs_peerOrg1the file name of the private key ski.

specific call

direct :

The CA client sends a registration request to the CA server node. The parameters are enrollmentID: username and affiliation: org1.department1, where the affiliation is specified in the yaml file of the CA node and can be modified. Register to return the secret to log in.

enroll:

  • setUserContext({username:username, password:secret})
  • _setUserFromConfig() , the CA client calls enroll(), sends the parameters enrollmentID: username, enrollmentSecret: password, the login returns the private key and certificate generated by the CA node
  • createUser() sends parameters username, mspid, cryptoContent (private key, certificate)
    to build a User object: _signingIdentity, _mspId, _cryptoSuite, _identity, _enrollmentSecret (the current version attribute is not assigned),
    where the private key is stored locally through CryptoSuit.importKey(private_key) , the file name is ski + '_priv'
    through setEnrollment() ——> importKey(certificate) The public key is generated through the certificate and stored locally, the file name is ski+'_pub'
  • Finally, call setUserContext(User object) again -> saveUserToStateStore() to save the Use object locally, the file name is username, and the content is the serialization of the User object (toString())

Summarize

  • Generate jwt, the token value needs to be used in subsequent requests
  • Generate a client instance by loading the configuration file (set the target blockchain network information and the local storage path of the user state and public and private keys)
  • Judgment (getUserContext), if the user is not logged in, get information from the configuration file (secret) to log in to admin
  • Through the CA service, the admin acts as the registrar to register the user
  • Log in the user and store the user state information and key pair locally (setUserContext is done in one step)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325917350&siteId=291194637