一 注册用户代码代码
var getRegisteredUsers = function(username, userOrg, isJson) {
var member;
var client = getClientForOrg(userOrg);
var enrollmentSecret = null;
// 设置公私钥存储的地方
return hfc.newDefaultKeyValueStore({
// 这里只要求path参数 来作为存储的地方
path: getKeyStoreForOrg(getOrgName(userOrg))
}).then((store) => {
// 设置状态持久化存储(如(证书,私钥。。))
client.setStateStore(store);
// clearing the user context before switching
client._userContext = null;
//1 获取用户信息 (从 内存–>statestore 依次查找)
return client.getUserContext(1)(username, true).then((user) => {
if (user && user.isEnrolled()) {
// 从持久化中 成功加载此 user
logger.info(‘Successfully loaded member from persistence’);
return user;
} else {
let caClient = caClients[userOrg];
//2 获得adminuser 来注册账户
return getAdminUser(userOrg)().then(function(adminUserObj) {
member = adminUserObj;
return caClient.register(2)({
enrollmentID: username,
// 与此用户关联的隶属关系
affiliation: userOrg + ‘.department1’
}, member); // 注册员
}).then((secret) => {
enrollmentSecret = secret;
logger.debug(username + ’ registered successfully’);
//3 注册成功后 拿着secret 来enroll
return caClient.enroll(3)({
enrollmentID: username,
enrollmentSecret: secret
});
}, (err) => {
logger.debug(username + ’ failed to register’);
return ‘’ + err;
//return ‘Failed to register ‘+username+’. Error: ’ + err.stack ? err.stack : err;
}).then((message) => { // enroll 返回的信息
if (message && typeof message == ‘string’ && message.includes(
‘Error:’)) {
logger.error(username + ’ enrollment failed’);
return message;
}
logger.debug(username + ’ enrolled successfully’);
// 构建user对象
member = new User(username);
member._enrollmentSecret = enrollmentSecret;
//4 设置此User实例的注册对象 来持久化在client中
return member.setEnrollment(message.key, message.certificate, getMspID(userOrg));
}).then(() => {
//5 保存用户的上下文环境(e.g 证书 私钥 ) 用户签名 各种请求
client.setUserContext(member);
return member;
}, (err) => {
logger.error(util.format(’%s enroll failed: %s’, username, err.stack ? err.stack : err));
return ‘’ + err;
});;
}
});
}).then((user) => {
// 6 返回用户信息
if (isJson && isJson=== true) {
var response = {
success: true,
secret: user._enrollmentSecret,
message: username + ’ enrolled Successfully’,
};
return response;
}
return user;
}, (err) => {
logger.error(util.format(‘Failed to get registered user: %s, error: %s’, username, err.stack ? err.stack : err));
return ‘’ + err;
});
};
二 代码里api追踪
()var getAdminUser = function(userOrg) {
var users = hfc.getConfigSetting(‘admins’);//获得用户的admin(0)
var username = users[0].username;
var password = users[0].secret;
var member;
var client = getClientForOrg(userOrg);
return hfc.newDefaultKeyValueStore({
path: getKeyStoreForOrg(getOrgName(userOrg))
}).then((store) => {
client.setStateStore(store);
// clearing the user context before switching
client._userContext = null;
return client.getUserContext(username, true).then((user) => {
if (user && user.isEnrolled()) {
logger.info(‘Successfully loaded member from persistence’);
return user;
} else {
let caClient = caClients[userOrg];
// need to enroll it with CA server
return caClient.enroll({
enrollmentID: username,
enrollmentSecret: password
}).then((enrollment) => {
logger.info(‘Successfully enrolled user ‘’ + username + ‘’’);
member = new User(username);
member.setCryptoSuite(client.getCryptoSuite());
return member.setEnrollment(enrollment.key, enrollment.certificate, getMspID(userOrg));
}).then(() => {
return client.setUserContext(member);
}).then(() => {
return member;
}).catch((err) => {
logger.error('Failed to enroll and persist user. Error: ’ + err.stack ?
err.stack : err);
return null;
});
}
});
});
};
(0)//Internal method to get an override setting to the configuration settings
//
module.exports.getConfigSetting = function(name, default_value) {
var config = this.getConfig();
return config.get(name, default_value);
};
(1)
@param {String} name - Optional. If not specified, will only return the current in-memory user context object, or null
* if none has been set. If “name” is specified, will also attempt to load it from the state store
* if search in memory failed.
* @param {boolean} checkPersistence - Optional. If specified and truthy, the method returns a Promise and will
* attempt to check the state store for the requested user by the “name”. If not
* specified or falsey, the method is synchronous and returns the requested user from memory
* @returns {Promise | User} Promise for the user object corresponding to the name, or null if the user does not exist or if the
* state store has not been set. If “checkPersistence” is not specified or falsey, then the user object
* is returned synchronously.
*/
getUserContext(name, checkPersistence) { // first check if only one param is passed in for "checkPersistence" if (typeof name === 'boolean' && name && typeof checkPersistence === 'undefined') throw new Error('Illegal arguments: "checkPersistence" is truthy but "name" is undefined'); if (typeof checkPersistence === 'boolean' && checkPersistence && (typeof name !== 'string' || name === null || name === '')) throw new Error('Illegal arguments: "checkPersistence" is truthy but "name" is not a valid string value'); var self = this; var username = name; if ((self._userContext && name && self._userContext.getName() === name) || (self._userContext && !name)) { if (typeof checkPersistence === 'boolean' && checkPersistence) return Promise.resolve(self._userContext); else return self._userContext; } else { if (typeof username === 'undefined' || !username) { if (typeof checkPersistence === 'boolean' && checkPersistence) return Promise.resolve(null); else return null; } // this could be because the application has not set a user context yet for this client, which would // be an error condiditon, or it could be that this app has crashed before and is recovering, so we // should allow the previously saved user context object to be deserialized // first check if there is a user context of the specified name in persistence if (typeof checkPersistence === 'boolean' && checkPersistence) { if (self._stateStore) { return self.loadUserFromStateStore(username).then( function(userContext) { if (userContext) { logger.debug('Requested user "%s" loaded successfully from the state store on this Client instance: name - %s', name, name); return self.setUserContext(userContext, false); } else { logger.debug('Requested user "%s" not loaded from the state store on this Client instance: name - %s', name, name); return null; } } ).then( function(userContext) { return Promise.resolve(userContext); } ).catch( function(err) { logger.error('Failed to load an instance of requested user "%s" from the state store on this Client instance. Error: %s', name, err.stack ? err.stack : err); return Promise.reject(err); } ); } else { // we don't have it in memory or persistence, just return null return Promise.resolve(null); } } else return null; } }
(2)
* Register the member and return an enrollment secret.
* @param {Object} req Registration request with the following fields:
*
- enrollmentID {string}. ID which will be used for enrollment
*
- enrollmentSecret {string}. Optional enrollment secret to set for the registered user.
* If not provided, the server will generate one.
*
- role {string}. An arbitrary string representing a role value for the user
*
- affiliation {string}. Affiliation with which this user will be associated, like a company or an organization
*
- maxEnrollments {number}. The maximum number of times this user will be permitted to enroll
*
- attrs {
{@link KeyValueAttribute}[]}. Array of key/value attributes to assign to the user.
* @param registrar {User}. The identity of the registrar (i.e. who is performing the registration)
* @returns {Promise} The enrollment secret to use when this user enrolls
*/
register(req, registrar) { if (typeof req === 'undefined' || req === null) { throw new Error('Missing required argument "request"'); } if (typeof req.enrollmentID === 'undefined' || req.enrollmentID === null) { throw new Error('Missing required argument "request.enrollmentID"'); } if (typeof req.maxEnrollments === 'undefined' || req.maxEnrollments === null) { // set maxEnrollments to 1 req.maxEnrollments = 1; } checkRegistrar(registrar); return this._fabricCAClient.register(req.enrollmentID, req.enrollmentSecret, req.role, req.affiliation, req.maxEnrollments, req.attrs, registrar.getSigningIdentity(5)()); * Register a new user and return the enrollment secret * @param {string} enrollmentID ID which will be used for enrollment * @param {string} enrollmentSecret Optional enrollment secret to set for the registered user. * If not provided, the server will generate one. * When not including, use a null for this parameter. * @param {string} role Optional type of role for this user. * When not including, use a null for this parameter. * @param {string} affiliation Affiliation with which this user will be associated * @param {number} maxEnrollments The maximum number of times the user is permitted to enroll * @param {KeyValueAttribute[]} attrs Array of key/value attributes to assign to the user * @param {SigningIdentity} signingIdentity The instance of a SigningIdentity encapsulating the * signing certificate, hash algorithm and signature algorithm * @returns {Promise} The enrollment secret to use when this user enrolls */ register(enrollmentID, enrollmentSecret, role, affiliation, maxEnrollments, attrs, signingIdentity) { var self = this; //all arguments are required if (!enrollmentID || !affiliation || !signingIdentity) { throw new Error('Missing required parameters. \'enrollmentID\', \'affiliation\', \ and \'signingIdentity\' are all required.'); } else if (!(typeof maxEnrollments === 'number')) { throw new Error('Missing required parameter. \'maxEnrollments\' must be a number'); } return new Promise(function (resolve, reject) { var regRequest = { 'id': enrollmentID, 'affiliation': affiliation, 'max_enrollments': maxEnrollments }; if(role) { regRequest.type = role; } if(attrs) { regRequest.attrs = attrs; } if (typeof enrollmentSecret === 'string' && enrollmentSecret !== '') { regRequest.secret = enrollmentSecret; } return self.post('register', regRequest, signingIdentity) .then(function (response) { return resolve(response.result.secret); }).catch(function (err) { return reject(err); }); }); }
(3)
* @typedef {Object} EnrollmentRequest
* @property {string} enrollmentID - The registered ID to use for enrollment
* @property {string} enrollmentSecret - The secret associated with the enrollment ID
* @property {string} profile - The profile name. Specify the ‘tls’ profile for a TLS certificate;
* otherwise, an enrollment certificate is issued.
* @property {AttributeRequest[]} attr_reqs - An array of {@link AttributeRequest}
*/
/** * Enroll the member and return an opaque member object. * @param req the {@link EnrollmentRequest} * @returns Promise for an object with "key" for private key and "certificate" for the signed certificate */ enroll(req) { var self = this; return new Promise(function (resolve, reject) { if (typeof req === 'undefined' || req === null) { logger.error('enroll() missing required argument "request"'); return reject(new Error('Missing required argument "request"')); } if (!req.enrollmentID) { logger.error('Invalid enroll request, missing enrollmentID'); return reject(new Error('req.enrollmentID is not set')); } if (!req.enrollmentSecret) { logger.error('Invalid enroll request, missing enrollmentSecret'); return reject(new Error('req.enrollmentSecret is not set')); } if(req.attr_reqs) { if(!Array.isArray(req.attr_reqs)) { logger.error('Invalid enroll request, attr_reqs must be an array of AttributeRequest objects'); return reject(new Error('req.attr_reqs is not an array')); } else { for(let i in req.attr_reqs) { let attr_req = req.attr_reqs[i]; if(!attr_req.name) { logger.error('Invalid enroll request, attr_reqs object is missing the name of the attribute'); return reject(new Error('req.att_regs is missing the attribute name')); } } } } //generate enrollment certificate pair for signing var opts; if (self.getCryptoSuite()._cryptoKeyStore) { opts = {ephemeral: false}; } else { opts = {ephemeral: true}; } self.getCryptoSuite().generateKey(opts) .then( function (privateKey) { //generate CSR using enrollmentID for the subject try { var csr = privateKey.generateCSR('CN=' + req.enrollmentID); self._fabricCAClient.enroll(req.enrollmentID, req.enrollmentSecret, csr, req.profile, req.attr_reqs)(4) .then( function (enrollResponse) { return resolve({ key: privateKey, certificate: enrollResponse.enrollmentCert, rootCertificate: enrollResponse.caCertChain }); }, function (err) { return reject(err); } ); } catch (err) { return reject(new Error(util.format('Failed to generate CSR for enrollmemnt due to error [%s]', err))); } }, function (err) { return reject(new Error(util.format('Failed to generate key for enrollment due to error [%s]', err))); } ); }); }
(4)
* Enroll a registered user in order to receive a signed X509 certificate * @param {string} enrollmentID The registered ID to use for enrollment * @param {string} enrollmentSecret The secret associated with the enrollment ID * @param {string} csr PEM-encoded PKCS#10 certificate signing request * @param {string} profile The profile name. Specify the 'tls' profile for a TLS certificate; otherwise, an enrollment certificate is issued. * @param {AttributeRequest[]} attr_reqs An array of {@link AttributeRequest} * @returns {Promise} {@link EnrollmentResponse} * @throws Will throw an error if all parameters are not provided * @throws Will throw an error if calling the enroll API fails for any reason */ enroll(enrollmentID, enrollmentSecret, csr, profile, attr_reqs) { var self = this; var numArgs = arguments.length; return new Promise(function (resolve, reject) { //check for required args if (numArgs < 3) { return reject(new Error('Missing required parameters. \'enrollmentID\', \'enrollmentSecret\' and \'csr\' are all required.')); } var requestOptions = { hostname: self._hostname, port: self._port, path: self._baseAPI + 'enroll', method: 'POST', auth: enrollmentID + ':' + enrollmentSecret, ca: self._tlsOptions.trustedRoots, rejectUnauthorized: self._tlsOptions.verify }; var enrollRequest = { caName: self._caName, certificate_request: csr }; if(profile) { enrollRequest.profile = profile; } if(attr_reqs) { enrollRequest.attr_reqs = attr_reqs; } var request = self._httpClient.request(requestOptions, function (response) { const responseBody = []; response.on('data', function (chunk) { responseBody.push(chunk); }); response.on('end', function () { var payload = responseBody.join(''); if (!payload) { reject(new Error( util.format('Enrollment failed with HTTP status code ', response.statusCode))); } //response should be JSON try { var res = JSON.parse(payload); if (res.success) { //we want the result field which is Base64-encoded PEM var enrollResponse = new Object(); // Cert field is Base64-encoded PEM enrollResponse.enrollmentCert = Buffer.from(res.result.Cert, 'base64').toString(); enrollResponse.caCertChain = Buffer.from(res.result.ServerInfo.CAChain, 'base64').toString(); return resolve(enrollResponse); } else { return reject(new Error( util.format('Enrollment failed with errors [%s]', JSON.stringify(res.errors)))); } } catch (err) { reject(new Error( util.format('Could not parse enrollment response [%s] as JSON due to error [%s]', payload, err))); } }); }); request.on('error', function (err) { reject(new Error(util.format('Calling enrollment endpoint failed with error [%s]', err))); }); let body = JSON.stringify(enrollRequest); request.write(body); request.end(); });
(5)
_getSigningIdentity(admin) {
logger.debug(’_getSigningIdentity - admin parameter is %s :%s’,(typeof admin),admin);
if(admin && this._adminSigningIdentity) {
return this._adminSigningIdentity;
} else {
if(this._userContext) {
return this._userContext.getSigningIdentity();
} else {
throw new Error(‘No identity has been assigned to this client’);
}
}
}
* Set the admin signing identity object. This method will only assign a
* signing identity for use by this client instance and will not persist
* the identity.
* @param {string} private_key - the private key PEM string
* @param {string} certificate the PEM-encoded string of certificate
* @param {string} mspid The Member Service Provider id for the local signing identity
*/
setAdminSigningIdentity(private_key, certificate, mspid) { logger.debug('setAdminSigningIdentity - start mspid:%s',mspid); if (typeof private_key === 'undefined' || private_key === null || private_key === '') { throw new Error('Invalid parameter. Must have a valid private key.'); } if (typeof certificate === 'undefined' || certificate === null || certificate === '') { throw new Error('Invalid parameter. Must have a valid certificate.'); } if (typeof mspid === 'undefined' || mspid === null || mspid === '') { throw new Error('Invalid parameter. Must have a valid mspid.'); } let crypto_suite = this.getCryptoSuite(); if(!crypto_suite) { crypto_suite = BaseClient.newCryptoSuite(); } const key = crypto_suite.importKey(private_key, {ephemeral : true}); const public_key = crypto_suite.importKey(certificate, {ephemeral: true}); this._adminSigningIdentity = new SigningIdentity(certificate, public_key, mspid, crypto_suite, new Signer(crypto_suite, key)); }