回顾
在前面介绍了java fabric的登记,如果想了解:
https://blog.csdn.net/datouniao1/article/details/103963631
那么接下来咱们来一起来探索另外的一个知识点 注册
环境准备
既然要注册用户,那么我们肯定要创建一个用户,如何来创建用户
在fabric-java-jdk中有关于User实现类的说法
红线圈住的是fabric-java-jdk自己实现的user方法,我们看到的是在1.4之后就没有LocalUser方法了,但是我们可以自己实现一个User接口,在fabric-java-jdk的测试用例中有SampleUser实现类,我们这个地方可以用这个实现类:
/*
* Copyright 2016 DTCC, Fujitsu Australia Software Technology - All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fabric.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Set;
import io.netty.util.internal.StringUtil;
import org.bouncycastle.util.encoders.Hex;
import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.security.CryptoSuite;
import org.hyperledger.fabric_ca.sdk.EnrollmentRequest;
import org.hyperledger.fabric_ca.sdk.HFCAClient;
import org.hyperledger.fabric_ca.sdk.exception.EnrollmentException;
import org.hyperledger.fabric_ca.sdk.exception.InvalidArgumentException;
import com.dao.util.StrUtil;
public class SampleUser implements User, Serializable {
private static final long serialVersionUID = 8077132186383604355L;
private String name;
private Set<String> roles;
private String account;
private String affiliation;
private String organization;
private String enrollmentSecret;
Enrollment enrollment = null; //need access in test env.
private transient SampleStore keyValStore;
private String keyValStoreName;
private transient CryptoSuite cryptoSuite;
public SampleUser(String name, String org, SampleStore fs, CryptoSuite cryptoSuite) {
this.name = name;
this.cryptoSuite = cryptoSuite;
this.keyValStore = fs;
this.organization = org;
this.keyValStoreName = toKeyValStoreName(this.name, org);
String memberStr = keyValStore.getValue(keyValStoreName);
if (null == memberStr) {
saveState();
} else {
restoreState();
}
}
static boolean isStored(String name, String org, SampleStore fs) {
return fs.hasValue(toKeyValStoreName(name, org));
}
public String getName() {
return this.name;
}
public Set<String> getRoles() {
return this.roles;
}
public void setRoles(Set<String> roles) {
this.roles = roles;
saveState();
}
public String getAccount() {
return this.account;
}
/**
* Set the account.
*
* @param account The account.
*/
public void setAccount(String account) {
this.account = account;
saveState();
}
public String getAffiliation() {
return this.affiliation;
}
/**
* Set the affiliation.
*
* @param affiliation the affiliation.
*/
public void setAffiliation(String affiliation) {
this.affiliation = affiliation;
saveState();
}
public Enrollment getEnrollment() {
return this.enrollment;
}
/**
* Determine if this name has been registered.
*
* @return {@code true} if registered; otherwise {@code false}.
*/
public boolean isRegistered() {
return !StrUtil.isObjBlank(enrollmentSecret);
}
/**
* Determine if this name has been enrolled.
*
* @return {@code true} if enrolled; otherwise {@code false}.
*/
public boolean isEnrolled() {
return this.enrollment != null;
}
/**
* Save the state of this user to the key value store.
*/
void saveState() {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
oos.flush();
keyValStore.setValue(keyValStoreName, Hex.toHexString(bos.toByteArray()));
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Restore the state of this user from the key value store (if found). If not found, do nothing.
*/
SampleUser restoreState() {
String memberStr = keyValStore.getValue(keyValStoreName);
if (null != memberStr) {
// The user was found in the key value store, so restore the
// state.
byte[] serialized = Hex.decode(memberStr);
ByteArrayInputStream bis = new ByteArrayInputStream(serialized);
try {
ObjectInputStream ois = new ObjectInputStream(bis);
SampleUser state = (SampleUser) ois.readObject();
if (state != null) {
this.name = state.name;
this.roles = state.roles;
this.account = state.account;
this.affiliation = state.affiliation;
this.organization = state.organization;
this.enrollmentSecret = state.enrollmentSecret;
this.enrollment = state.enrollment;
this.mspId = state.mspId;
return this;
}
} catch (Exception e) {
throw new RuntimeException(String.format("Could not restore state of member %s", this.name), e);
}
}
return null;
}
public String getEnrollmentSecret() {
return enrollmentSecret;
}
public void setEnrollmentSecret(String enrollmentSecret) {
this.enrollmentSecret = enrollmentSecret;
saveState();
}
public void setEnrollment(Enrollment enrollment) {
this.enrollment = enrollment;
saveState();
}
public void setIdemixEnrollment(Enrollment enrollment) {
this.enrollment = enrollment;
}
public static String toKeyValStoreName(String name, String org) {
return "user." + name + org;
}
public String getMspId() {
return mspId;
}
String mspId;
public void setMspId(String mspID) {
this.mspId = mspID;
saveState();
}
}
还有另外的几个方法:
SampleStore.java
/*
* Copyright 2016, 2017 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fabric.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.util.encoders.Hex;
import org.hyperledger.fabric.sdk.Channel;
import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.HFClient;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.security.CryptoSuite;
/**
* A local file-based key value store.
*/
public class SampleStore {
private String file;
private Log logger = LogFactory.getLog(SampleStore.class);
private CryptoSuite cryptoSuite;
public SampleStore(File file) {
this.file = file.getAbsolutePath();
}
/**
* Get the value associated with name.
*
* @param name
* @return value associated with the name
*/
public String getValue(String name) {
Properties properties = loadProperties();
return properties.getProperty(name);
}
/**
* Has the value present.
*
* @param name
* @return true if it's present.
*/
public boolean hasValue(String name) {
Properties properties = loadProperties();
return properties.containsKey(name);
}
private Properties loadProperties() {
Properties properties = new Properties();
try (InputStream input = new FileInputStream(file)) {
properties.load(input);
input.close();
} catch (FileNotFoundException e) {
logger.info(String.format("Could not find the file \"%s\"", file));
} catch (IOException e) {
logger.warn(String.format("Could not load keyvalue store from file \"%s\", reason:%s",
file, e.getMessage()));
}
return properties;
}
/**
* Set the value associated with name.
*
* @param name The name of the parameter
* @param value Value for the parameter
*/
public void setValue(String name, String value) {
Properties properties = loadProperties();
try (
OutputStream output = new FileOutputStream(file)
) {
properties.setProperty(name, value);
properties.store(output, "");
output.close();
} catch (IOException e) {
logger.warn(String.format("Could not save the keyvalue store, reason:%s", e.getMessage()));
}
}
private final Map<String, SampleUser> members = new HashMap<>();
/**
* Get the user with a given name
*
* @param name
* @param org
* @return user
*/
public SampleUser getMember(String name, String org) {
// Try to get the SampleUser state from the cache
SampleUser sampleUser = members.get(SampleUser.toKeyValStoreName(name, org));
if (null != sampleUser) {
return sampleUser;
}
// Create the SampleUser and try to restore it's state from the key value store (if found).
sampleUser = new SampleUser(name, org, this, cryptoSuite);
return sampleUser;
}
/**
* Check if store has user.
*
* @param name
* @param org
* @return true if the user exists.
*/
public boolean hasMember(String name, String org) {
// Try to get the SampleUser state from the cache
if (members.containsKey(SampleUser.toKeyValStoreName(name, org))) {
return true;
}
return SampleUser.isStored(name, org, this);
}
/**
* Get the user with a given name
*
* @param name
* @param org
* @param mspId
* @param privateKeyFile
* @param certificateFile
* @return user
* @throws IOException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws InvalidKeySpecException
*/
public SampleUser getMember(String name, String org, String mspId, File privateKeyFile,
File certificateFile) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
try {
// Try to get the SampleUser state from the cache
SampleUser sampleUser = members.get(SampleUser.toKeyValStoreName(name, org));
if (null != sampleUser) {
return sampleUser;
}
// Create the SampleUser and try to restore it's state from the key value store (if found).
sampleUser = new SampleUser(name, org, this, cryptoSuite);
sampleUser.setMspId(mspId);
String certificate = new String(IOUtils.toByteArray(new FileInputStream(certificateFile)), "UTF-8");
PrivateKey privateKey = getPrivateKeyFromBytes(IOUtils.toByteArray(new FileInputStream(privateKeyFile)));
sampleUser.setEnrollment(new SampleStoreEnrollement(privateKey, certificate));
sampleUser.saveState();
return sampleUser;
} catch (IOException e) {
e.printStackTrace();
throw e;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw e;
} catch (NoSuchProviderException e) {
e.printStackTrace();
throw e;
} catch (InvalidKeySpecException e) {
e.printStackTrace();
throw e;
} catch (ClassCastException e) {
e.printStackTrace();
throw e;
}
}
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
static PrivateKey getPrivateKeyFromBytes(byte[] data) throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
final Reader pemReader = new StringReader(new String(data));
final PrivateKeyInfo pemPair;
try (PEMParser pemParser = new PEMParser(pemReader)) {
pemPair = (PrivateKeyInfo) pemParser.readObject();
}
PrivateKey privateKey = new JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getPrivateKey(pemPair);
return privateKey;
}
// Use this to make sure SDK is not dependent on HFCA enrollment for non-Idemix
static final class SampleStoreEnrollement implements Enrollment, Serializable {
private static final long serialVersionUID = -2784835212445309006L;
private final PrivateKey privateKey;
private final String certificate;
SampleStoreEnrollement(PrivateKey privateKey, String certificate) {
this.certificate = certificate;
this.privateKey = privateKey;
}
public PrivateKey getKey() {
return privateKey;
}
public String getCert() {
return certificate;
}
}
void saveChannel(Channel channel) throws IOException, InvalidArgumentException {
setValue("channel." + channel.getName(), Hex.toHexString(channel.serializeChannel()));
}
Channel getChannel(HFClient client, String name) throws IOException, ClassNotFoundException, InvalidArgumentException {
Channel ret = null;
String channelHex = getValue("channel." + name);
if (channelHex != null) {
ret = client.deSerializeChannel(Hex.decode(channelHex));
}
return ret;
}
public void storeClientPEMTLSKey(SampleOrg sampleOrg, String key) {
setValue("clientPEMTLSKey." + sampleOrg.getName(), key);
}
public String getClientPEMTLSKey(SampleOrg sampleOrg) {
return getValue("clientPEMTLSKey." + sampleOrg.getName());
}
public void storeClientPEMTLCertificate(SampleOrg sampleOrg, String certificate) {
setValue("clientPEMTLSCertificate." + sampleOrg.getName(), certificate);
}
public String getClientPEMTLSCertificate(SampleOrg sampleOrg) {
return getValue("clientPEMTLSCertificate." + sampleOrg.getName());
}
}
以及类:
SampleOrg.java
package com.fabric.util;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric_ca.sdk.HFCAClient;
/*
* Copyright 2016, 2017 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Sample Organization Representation
*
* Keeps track which resources are defined for the Organization it represents.
*
*/
public class SampleOrg {
final String name;
final String mspid;
HFCAClient caClient;
Map<String, User> userMap = new HashMap<String, User>();
Map<String, String> peerLocations = new HashMap<String, String>();
Map<String, String> ordererLocations = new HashMap<String, String>();
Map<String, String> eventHubLocations = new HashMap<String, String>();
private SampleUser admin;
private String caLocation;
private Properties caProperties = null;
private SampleUser peerAdmin;
private String domainName;
public String getCAName() {
return caName;
}
private String caName;
public SampleOrg(String name, String mspid) {
this.name = name;
this.mspid = mspid;
}
public SampleUser getAdmin() {
return admin;
}
public void setAdmin(SampleUser admin) {
this.admin = admin;
}
public String getMSPID() {
return mspid;
}
public String getCALocation() {
return this.caLocation;
}
public void setCALocation(String caLocation) {
this.caLocation = caLocation;
}
public void addPeerLocation(String name, String location) {
peerLocations.put(name, location);
}
public void addOrdererLocation(String name, String location) {
ordererLocations.put(name, location);
}
public void addEventHubLocation(String name, String location) {
eventHubLocations.put(name, location);
}
public String getPeerLocation(String name) {
return peerLocations.get(name);
}
public String getOrdererLocation(String name) {
return ordererLocations.get(name);
}
public String getEventHubLocation(String name) {
return eventHubLocations.get(name);
}
public Set<String> getPeerNames() {
return Collections.unmodifiableSet(peerLocations.keySet());
}
public Set<String> getOrdererNames() {
return Collections.unmodifiableSet(ordererLocations.keySet());
}
public Set<String> getEventHubNames() {
return Collections.unmodifiableSet(eventHubLocations.keySet());
}
public HFCAClient getCAClient() {
return caClient;
}
public void setCAClient(HFCAClient caClient) {
this.caClient = caClient;
}
public String getName() {
return name;
}
public void addUser(SampleUser user) {
userMap.put(user.getName(), user);
}
public User getUser(String name) {
return userMap.get(name);
}
public Collection<String> getOrdererLocations() {
return Collections.unmodifiableCollection(ordererLocations.values());
}
public Collection<String> getEventHubLocations() {
return Collections.unmodifiableCollection(eventHubLocations.values());
}
public void setCAProperties(Properties caProperties) {
this.caProperties = caProperties;
}
public Properties getCAProperties() {
return caProperties;
}
public SampleUser getPeerAdmin() {
return peerAdmin;
}
public void setPeerAdmin(SampleUser peerAdmin) {
this.peerAdmin = peerAdmin;
}
public void setDomainName(String domainName) {
this.domainName = domainName;
}
public String getDomainName() {
return domainName;
}
public void setCAName(String caName) {
this.caName = caName;
}
}
上面的几个类都是测试提供的方法,我们可以将其复制,copy到自己的代码里面作为自己User 接口实现方法
注册流程
流程可以分为这样的几步
1、首先是 用户注册 ,服务器会返回一个注册的密码
2. 新用户用id和服务器返回的注册密码登记,服务器会返回该用户的证书和私钥
根据这样的两个步骤,我们首先来看第一步,用户注册
用户注册
我们在注册用户之前,我们需要做的是通知服务器,我们现在要注册用户了,能不能给这个用户一个密码,让这个用户可以访问我们系统
通知服务要密码,这个过程是登记用户
,那么谁来登记这个用户,应该是连接这个JDK和服务器之前的管理员
我们来看这个接口:
/*
* Copyright 2016, 2017 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hyperledger.fabric.sdk;
import java.security.PrivateKey;
/**
* Interface which is the contract between the Certificate Authority provider and the SDK.
*/
public interface Enrollment {
/**
* Get the user's private key
*
* @return private key.
*/
PrivateKey getKey();
/**
* Get the user's signed certificate.
*
* @return a certificate.
*/
String getCert();
}
这个接口的解释是这样的:用于连接jdk和权威证书的一个接口
我们需要获取这样的一个接口的实例,我们在上一节的登记中根据管理员和密码已经可以获取到一个接口实例
这是一种获取方法,还有一种方法是我们通过证书和私钥来获取这个实例
这个地方我们就先用这一个方法,我们在下一篇不可中将会给出
接着我们就用上面创建的enrollment作为中间的使者
public static void main(String[] args) {
try {
String caUrl = "http://***.**.***.**:7054";
CryptoSuite cs = CryptoSuite.Factory.getCryptoSuite();
Properties prop = new Properties();
prop.put("verify", false);
HFCAClient caClient = HFCAClient.createNewInstance(caUrl, prop);
caClient.setCryptoSuite(cs);
Enrollment enrollment_admin = caClient.enroll("admin", "adminpw");
SampleStore sampleStore;
SampleUser admin;
File sampleStoreFile = new File(System.getProperty("java.io.tmpdir") + "/HFCSampletest.properties");
if (sampleStoreFile.exists()) { // For testingstart fresh
sampleStoreFile.delete();
}
sampleStore = new
SampleStore(sampleStoreFile);
sampleStoreFile.deleteOnExit();
admin = sampleStore.getMember("admin", "adminpw");
admin.setEnrollment(enrollment_admin);
RegistrationRequest regreq = new RegistrationRequest("name", "org1.department1");
regreq.setEnrollmentID("8880");
String str = caClient.register(regreq, admin);
System.out.println(str);
String str1 = "bcaHldHlonNC";
Enrollment enrollment1 = caClient.enroll("8888", str1);
System.out.println(enrollment1.getCert());
System.out.println(enrollment1.getKey());
} catch (Exception e) {
e.printStackTrace();
}
// https://www.jianshu.com/p/cfb087b56324
// https://www.jianshu.com/p/316b2f5e31a7
}
上面就实现了新用户的注册成功
方法最上面的部分是登记