fabric项目设置用户权限,实现链码层次不同级别的权限控制

在项目中一般需要设置不同用户的不同权限,fabric中的链码执行同样如此,可以通过用户标签来实现。
流程:sdk申请用户时,指定用户标签,链码执行时获取对应标签实现链码调用权限验证。

sdk代码(注册用户):

 /**
     * 注册用户并进行登记
     * @param orgName			所在组织
     * @param userName			用户名
     * @param pwd				用户密码
     * @return 			一个新的用户
     */
    public FabricUser registerAndEnrolledUser(String orgName, String userName, String pwd) throws Exception {

        FabricUser user = getUser(orgName, userName);

        RegistrationRequest request = new RegistrationRequest(userName, orgName.toLowerCase() + AFFILIATION);
        request.setSecret(pwd);

        //开始设置值
        request.addAttribute(new Attribute("org","org1"));
        request.addAttribute(new Attribute("peer","peer0.org1.example.com"));
        request.addAttribute(new Attribute("user", "fang"));
        request.addAttribute(new Attribute("dept", "test"));


        EnrollmentRequest req = new EnrollmentRequest();
        req.addAttrReq(); // empty ensure no attributes.

        user.setEnrollmentSecret(ca.register(request, admin));
        if (!user.getEnrollmentSecret().equals(pwd)) {
            throw new RuntimeException("设置密码异常,您设置的密码与系统返回的密码不一致:yourPwd:" + pwd + ", system:" + user.getEnrollmentSecret());
        }
        user.setEnrollment(ca.enroll(userName, pwd, req));
        //测试
        user.setMspId(orgName + "MSP");
        client.setUserContext(user);

        return user;
    }

链码操作代码:


func (t *TestChaincode) getUser(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	logger := getLogger(stub)

	logger.Info(fmt.Sprintf("get args: %s", args))

	//getting submitter of the transaction
	logger.Info("begin to read userInfo")
	sinfo, err := cid.New(stub)
	if err != nil {
		logger.Error(fmt.Sprintf("get submitter of the transaction: %s", sinfo))
		return shim.Error(err.Error())
	}
	id, _ := sinfo.GetID()
	logger.Info(fmt.Sprintf("get clientIdentityId: %s", id))
	mspId, _ := sinfo.GetMSPID()
	logger.Info(fmt.Sprintf("get clientIdentityMSPId: %s", mspId))

	//读取dept的相关值
	dv, df, err := sinfo.GetAttributeValue("dept")
	if err != nil {
		logger.Error(fmt.Sprintf("get deptAttrVal err: %s", err.Error()))
	} else {
		if df {
			logger.Info(fmt.Sprintf("get deptAttrVal: %s", dv))
		} else {
			logger.Debug(fmt.Sprintf("not found deptAttrbute"))
		}
	}

	//读取org
	ov, of, err := sinfo.GetAttributeValue("org")
	if err != nil {
		logger.Error(fmt.Sprintf("get orgAttrVal err: %s", err.Error()))
	} else {
		if of {
			logger.Info(fmt.Sprintf("got orgAttrVal: %s", ov))
		} else {
			logger.Debug(fmt.Sprintf("not found orgAttrbute"))
		}
	}

	//读取peer
	pv, pf, err := sinfo.GetAttributeValue("peer")
	if err != nil {
		logger.Error(fmt.Sprintf("get peerAttrVal err: %s", err.Error()))
	} else {
		if pf {
			logger.Info(fmt.Sprintf("got peerAttrVal: %s", pv))
		} else {
			logger.Debug(fmt.Sprintf("not found peerAttrbute"))
		}
	}
	//读取user
	uv, uf, err := sinfo.GetAttributeValue("user")
	if err != nil {
		logger.Error(fmt.Sprintf("get userAttrVal err: %s", err.Error()))
	} else {
		if uf {
			logger.Info(fmt.Sprintf("got userAttrVal: %s", uv))
		} else {
			logger.Debug(fmt.Sprintf("not found userAttrbute"))
		}
	}

	return shim.Success([]byte("请看日志"))
}

日志部分截图:

这里写图片描述

通过自定义标签即可实现权限的基本控制,具体设计就看公司项目了。

其它代码:

@Slf4j
public class PeerConfig {

    private static final String PROP_BASE = "org.hyperledger.fabric.bdo.";

    private static final String GOSSIP_WAIT_TIME = PROP_BASE + "GossipWaitTime";
    private static final String INVOKE_WAIT_TIME = PROP_BASE + "InvokeWaitTime";
    private static final String DEPLOY_WAIT_TIME = PROP_BASE + "DeployWaitTime";
    private static final String PROPOSAL_WAIT_TIME = PROP_BASE + "ProposalWaitTime";
    private static final String BDO_CHANNEL_NAME = PROP_BASE + "ChannelName";

    private static final String INTEGRATIONTESTS_ORG = PROP_BASE + "org.";

    private static final Pattern ORG_PAT = Pattern.compile("^" + Pattern.quote(INTEGRATIONTESTS_ORG) + "([^\\.]+)\\.mspid$");

    private static final Properties SDK_PROP = new Properties();

    private boolean runningTLS;
    private boolean runningFabricCATLS;
    private boolean runningFabricTLS;

    private static final HashMap<String, FabricOrg> ORGS = new HashMap<>();

    public static PeerConfig peerConfig = null;

    public static PeerConfig getInstance() {
        if (peerConfig == null) {
            synchronized (PeerConfig.class) {
                if (peerConfig == null) {
                    peerConfig = new PeerConfig();
                }
            }
        }

        return peerConfig;
    }

    private PeerConfig() {
        log.info("初始化配置文件");
        File loadFile;
        FileInputStream configProps;

        try {
            loadFile = ResourceUtils.getFile(Consts.CHAIN_PATH + "utils.properties");
            log.info(String.format("从 %s 下加载配置文件,文件是否存在:%b", loadFile.toString(), loadFile.exists()));
            configProps = new FileInputStream(loadFile);

            SDK_PROP.load(configProps);

        } catch (FileNotFoundException e) {
            log.error("配置文件丢失,请核实");
        } catch (IOException e) {
            log.error("出现了异常:{}", e.getMessage());
        } finally {

            //为什么要加这一句
            defaultProperty(INTEGRATIONTESTS_ORG, null);
            runningTLS = true;
            runningFabricCATLS = true;
            runningFabricTLS = runningTLS;

            for (Map.Entry<Object, Object> x : SDK_PROP.entrySet()) {
                final String key = x.getKey() + "";
                final String val = x.getValue() + "";

                if (key.startsWith(INTEGRATIONTESTS_ORG)) {
                    Matcher match = ORG_PAT.matcher(key);
                    if (match.matches() && match.groupCount() == 1) {
                        String orgName = match.group(1).trim();
                        ORGS.put(orgName, new FabricOrg(orgName, val.trim()));
                    }
                }
            }

            log.info(JSON.toJSONString(SDK_PROP));
            for (Map.Entry<String, FabricOrg> org : ORGS.entrySet()) {

                final FabricOrg fabricOrg = org.getValue();
                final String orgName = org.getKey();

                String peerNames = SDK_PROP.getProperty(INTEGRATIONTESTS_ORG + orgName + ".peer_locations");
                String[] ps = peerNames.split("[ \t]*,[ \t]*");
                for (String peer : ps) {
                    String[] nl = peer.split("[ \t]*@[ \t]*");
                    fabricOrg.addPeerLocation(nl[0], grpcTLSify(nl[1]));
                }

                final String domainName = SDK_PROP.getProperty(INTEGRATIONTESTS_ORG + orgName + ".domname");

                fabricOrg.setDomainName(domainName);
                String ordererNames = SDK_PROP.getProperty(INTEGRATIONTESTS_ORG + orgName + ".orderer_locations");
                ps = ordererNames.split("[ \t]*,[ \t]*");
                for (String peer : ps) {
                    String[] nl = peer.split("[ \t]*@[ \t]*");
                    fabricOrg.addOrdererLocation(nl[0], nl[1]);
                }

                String eventHubNames = SDK_PROP.getProperty(INTEGRATIONTESTS_ORG + orgName + ".eventhub_locations");
                ps = eventHubNames.split("[ \t]*,[ \t]*");
                for (String peer : ps) {
                    String[] nl = peer.split("[ \t]*@[ \t]*");
                    fabricOrg.addEventHubLocation(nl[0], grpcTLSify(nl[1]));
                }

                fabricOrg.setCaLocation(httpTLSify(SDK_PROP.getProperty(INTEGRATIONTESTS_ORG + org.getKey() + ".ca_location")));

                if (runningFabricCATLS) {
                    log.info("loading fabric ca tls cert");
                    String cert = Consts.CHAIN_PATH + "/e2e/channel/crypto-config/peerOrganizations/DNAME/ca/ca.DNAME-cert.pem".replaceAll("DNAME", domainName);
                    log.info("tls cert path:" + cert);
                    File cf;
                    try {
                        cf = ResourceUtils.getFile(cert);
                    } catch (FileNotFoundException e) {
                        throw new RuntimeException("证书文件不存在:" + e.getMessage());
                    }
//                    if (!cf.exists() || !cf.isFile()) {
//                        throw new RuntimeException("证书文件不存在:" + cf.getAbsolutePath());
//                    }
                    Properties properties = new Properties();
                    properties.setProperty("pemFile", cf.getAbsolutePath());

                    properties.setProperty("allowAllHostNames", "true");

                    fabricOrg.setCaProperties(properties);
                }

            }
            log.info(JSON.toJSONString(SDK_PROP));
        }
    }

    public boolean isRunningTLS(){
        return runningTLS;
    }

    private String httpTLSify(String location) {
        location = location.trim();

        return runningFabricCATLS ? location.replaceFirst("^http://", "https://") : location;
    }

    private String grpcTLSify(String location) {
        location = location.trim();
        Exception e = Utils.checkGrpcUrl(location);
        if (e != null) {
            throw new RuntimeException(String.format("grpc指定的url:%s 参数异常", location), e);
        }
        log.info(runningFabricTLS ? location.replaceFirst("^grpc://", "^grpcs://") : location);
        return runningFabricTLS ? location.replaceFirst("^grpc://", "^grpcs://") : location;
    }


    private String getProperty(String property) {
        String ret = SDK_PROP.getProperty(property);
        if (null == ret) {
            log.warn(String.format("没有发现该属性:%s", property));
        }
        return ret;
    }

    private static void defaultProperty(String key, String value) {

        String ret = System.getProperty(key);
        if (ret != null) {
            SDK_PROP.put(key, value);
        } else {
            String envKey = key.toUpperCase().replaceAll("\\.", "_");
            ret = System.getenv(envKey);
            if (null != ret) {
                SDK_PROP.put(key, value);
            } else {
                if (null == SDK_PROP.getProperty(key) && value != null) {
                    SDK_PROP.put(key, value);
                }
            }
        }

    }

    public int getTransactionWaitTime() {
        return Integer.parseInt(getProperty(INVOKE_WAIT_TIME));
    }

    public int getDeployWaitTime() {
        return Integer.parseInt(getProperty(DEPLOY_WAIT_TIME));
    }

    public int getGossipWaitTime() {
        return Integer.parseInt(getProperty(GOSSIP_WAIT_TIME));
    }

    public int getProposalWaitTime() {
        return Integer.parseInt(getProperty(PROPOSAL_WAIT_TIME));
    }

    public String getDefaultChannelName(){
        return getProperty(BDO_CHANNEL_NAME);
    }

    public Collection<FabricOrg> getIntegrationTestFabricOrgs() {
        return Collections.unmodifiableCollection(ORGS.values());
    }

    public FabricOrg getIntegrationFabricOrg(String name) {
        return ORGS.get(name);
    }

    public String getPeerProperty(String org) {
        org = org.substring(0, 1).toUpperCase() + org.substring(1);
        return getProperty(INTEGRATIONTESTS_ORG + "peer" + org + ".peer_locations");
    }

    public String getOrdererProperty() {
        // org.hyperledger.fabric.wnzx.org.peerOrg1.orderer_locations
        return getProperty(INTEGRATIONTESTS_ORG + "peerOrg1.orderer_locations");
    }

    public Properties getPeerProperties(String name) {
        return getEndPointProperties("peer", name);
    }

    public Properties getOrdererProperties(String name) {
        return getEndPointProperties("orderer", name);
    }

    public Properties getEndPointProperties(final String type, final String name) {

        final String domainName = getDommainName(name);

        File cert = Paths.get(getChannelPath(),
                "crypto-config/ordererOrganizations".replace("orderer", type),
                domainName,
                type + "s",
                name,
                "tls/server.crt")
                .toFile();
        if (!cert.exists()) {
            throw new RuntimeException(String.format("%s 文件加载失败,在指定地址未找到:%s", name, cert.getAbsolutePath()));
        }

        Properties ret = new Properties();
        ret.setProperty("pemFile", cert.getAbsolutePath());
        ret.setProperty("hostnameOverride", name);
        ret.setProperty("sslProvider", "openSSL");
        ret.setProperty("negotiationType", "TLS");

        return ret;
    }

    private String getDommainName(final String name) {
        int dot = name.indexOf(".");
        if (-1 == dot) {
            return null;
        } else {
            return name.substring(dot + 1);
        }
    }

    public Properties getEventHubProperties(String name) {
        return getEndPointProperties("peer", name);
    }

    public String getChannelPath() {
        return Consts.CHAIN_PATH + "e2e/channel";
    }
}



@Slf4j
public class CAClient {

    private static final String AFFILIATION = ".department1";

    private HFCAClient caClient;

    private CryptoSuite cryptosuite;

    private HFClient client = HFClient.createNewInstance();

    private PeerConfig config = PeerConfig.getInstance();

    private CAClient() {
        try {
            log.debug("init crypto...");
            cryptosuite = CryptoSuite.Factory.getCryptoSuite();
            client.setCryptoSuite(cryptosuite);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static CAClient createNewInstance() {
        return new CAClient();
    }

    public HFClient getClient() {
        return client;
    }


    public String register(FabricUser register, String userName, String secret, String affiliation, String type, Map<String, String> attrs) throws CAException {
        return register(register, userName, secret, affiliation, type, -1, attrs);
    }

    /**
     * @param register 注册发起人
     * @param userName  注册用户名
     * @param secret  用户密码
     * @param affiliation 用户关联关系
     * @param type        用户类型
     * @param maxEnrollments 最大注册数量
     *
     * @throws CAException 注册异常
     */
    public String register(FabricUser register, String userName, String secret, String affiliation, String type, int maxEnrollments, Map<String, String> attrs) throws CAException {
        try {
            initClient(register);

            RegistrationRequest request = new RegistrationRequest(userName, affiliation);
            request.setAffiliation(affiliation);
            request.setEnrollmentID(userName);
            request.setType(type);
            if (!"".equals(secret)){
                request.setSecret(secret);
            }

            request.setMaxEnrollments(maxEnrollments);
            for (String key : attrs.keySet()){
                request.addAttribute(new Attribute(key, attrs.get(key)));
            }

            return caClient.register(request, register);

        } catch (Exception e) {
            e.printStackTrace();
            throw new CAException(e.getMessage());
        }
    }

    /**
     * 注册用户并进行登记
     * @param orgName			所在组织
     * @param userName			用户名
     * @param pwd				用户密码
     * @return 			一个新的用户
     */
    public FabricUser registerAndEnrolledUser(String orgName, String userName, String pwd, FabricUser admin, Map<String, String> attrs) throws CAException {

        try {
            initClient(admin);

            FabricUser user = new FabricUser(userName, orgName);

            RegistrationRequest request = new RegistrationRequest(userName, orgName.toLowerCase() + AFFILIATION);
            request.setSecret(pwd);

            //开始设置值(进行权限控制)
            for (String key : attrs.keySet()) {
                request.addAttribute(new Attribute(key, attrs.get(key)));
            }

            user.setEnrollmentSecret(caClient.register(request, admin));
            if (!user.getEnrollmentSecret().equals(pwd)) {
                throw new RuntimeException("设置密码异常,您设置的密码与系统返回的密码不一致:yourPwd:" + pwd + ", system:" + user.getEnrollmentSecret());
            }
            user.setEnrollment(caClient.enroll(userName, pwd));
            //测试
            user.setMspId(orgName + "MSP");
            client.setUserContext(user);

            return user;
        } catch (Exception e) {
            e.printStackTrace();
            throw new CAException(e.getMessage());
        }
    }

    /**
     * 撤销用户
     */
    public void revokeUser(FabricUser admin, String userName, String reason) throws CAException {
        try {
            initClient(admin);
            caClient.revoke(admin, userName, reason);
        } catch (Exception e) {
            e.printStackTrace();
            throw new CAException(e.getMessage());
        }
    }

    private void initClient(FabricUser user) throws MalformedURLException {
        log.info(user.getOrganization()+"'s."+user.getName()+" begin to enroll fabric CA");
        FabricOrg org = config.getIntegrationFabricOrg("peer" + user.getOrganization());
        log.info("get organization's config file");
        String caLocation = org.getCaLocation();

        caClient = HFCAClient.createNewInstance(caLocation, org.getCaProperties());
        caClient.setCryptoSuite(cryptosuite);
    }

    /**
     * 登录一个用户
     */
    public FabricUser enroll(FabricUser user) throws CAException {
        try {
            initClient(user);

            EnrollmentRequest req = new EnrollmentRequest();

            Enrollment enrollment = caClient.enroll(user.getName(), user.getEnrollmentSecret(), req);

            if (enrollment == null) {
                log.error("login to ca fail, please check userinfo");
                throw new CAException("登录失败,请检查用户信息。");
            }

            user.setEnrollment(enrollment);
            user.setMspId(user.getOrganization() + "MSP");
            client.setUserContext(user);

            return user;
        } catch (Exception e) {
            throw new CAException(e.getMessage());
        }

    }

    public FabricUser reenroll(FabricUser user) throws CAException {
        try {
            initClient(user);
            Enrollment e = caClient.reenroll(user);
            if (e == null){
                return null;
            }
            user.setEnrollment(e);
            client.setUserContext(user);
            return user;
        } catch (Exception e) {
            e.printStackTrace();
            throw new CAException(e.getMessage());
        }
    }

    public HFCAIdentity readIdentified(FabricUser user) throws CAException {
        try {
            initClient(user);
            HFCAIdentity hfcaIdentity = caClient.newHFCAIdentity(user.getName());
            hfcaIdentity.read(user);
            return hfcaIdentity;
        } catch (InvalidArgumentException e) {
            e.printStackTrace();
            throw new CAException("参数异常:" + e.getMessage());
        } catch (IdentityException e) {
            e.printStackTrace();
            throw new CAException("身份异常:" + e.getMessage());
        } catch (MalformedURLException e) {
            e.printStackTrace();
            throw new CAException(e.getMessage());
        }
    }

    public HFCAAffiliation readAffiliation(FabricUser user) throws CAException {
        HFCAAffiliation hfcaAffiliation;
        try {
            hfcaAffiliation = caClient.newHFCAAffiliation(user.getName());
            hfcaAffiliation.read(user);
            return hfcaAffiliation;
        } catch (InvalidArgumentException e) {
            e.printStackTrace();
            throw new CAException("参数异常:" + e.getMessage());
        } catch (AffiliationException e) {
            e.printStackTrace();
            throw new CAException("身份异常:" + e.getMessage());
        }
    }

}


@Slf4j
@Data
public class FabricUser implements User {

    /**
     * 名称
     */
    private String name;

    /**
     * 权限
     */
    private Set<String> roles;

    /**
     * 账户
     */
    private String account;

    /**
     * 用户关联关系
     */
    private String affiliation;

    /**
     * 组织
     */
    private String organization;


    /**
     * 秘钥
     */
    private String enrollmentSecret;

    /**
     * mspid
     */
    private String mspId;

    /**
     * 登录后返回的证书和私钥
     */
    Enrollment enrollment = null;

    private Attrs attrs;

    public FabricUser(String name, String org) {
        this.name = name;
        this.organization = org;
    }

    /**
     * 设置账户信息并将用户状态更新只存储配置对象
     */
    public void setAccount(String account) {
        this.account = account;
    }

    @Override
    public String getAccount() {
        return this.account;
    }

    @Override
    public String getAffiliation() {
        return this.affiliation;
    }

    @Override
    public Enrollment getEnrollment() {
        return this.enrollment;
    }


    @Override
    public String getMspId() {
        return this.mspId;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Set<String> getRoles(){
        return this.roles;
    }

    public String getEnrollmentSecret() {
        return enrollmentSecret;
    }

    /**
     * 设置注册操作的秘钥信息将用户状态更新至存储配置对象
     */
    public void setEnrollmentSecret(String enrollmentSecret) {
        this.enrollmentSecret = enrollmentSecret;
    }

    /**
     * 设置注册登记操作信息并将用户状态更新只存储配置对象
     */
    public void setEnrollment(Enrollment enrollment) {
        this.enrollment = enrollment;
    }

    /**
     * 确定这个名称是否已注册
     */
    public boolean isRegistered() {
        return !"".equals(enrollmentSecret) && enrollmentSecret != null;
    }

    /**
     * 是否已经登录
     */
    public boolean isEnrolled() {
        return this.enrollment != null;
    }

    public String getOrganization() {
        return organization;
    }

    public void setOrganization(String org) {
        this.organization = org;
    }

    public Attrs getX509CertExtension() throws Exception {
        if (!isEnrolled()){
            throw new CAException("用户未登录");
        }
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(enrollment.getCert().getBytes()));
//        System.out.println("读取Cer证书信息...");
//        System.out.println("x509Certificate_SerialNumber_序列号__: " + x509Certificate.getSerialNumber());
//        System.out.println("x509Certificate_getIssuerDN_发布方标识名__: " + x509Certificate.getIssuerDN());
//        System.out.println("x509Certificate_getSubjectDN_主体标识__: " + x509Certificate.getSubjectDN());
//        System.out.println("x509Certificate_getSignAlgOID_证书算法OID字符串__: " + x509Certificate.getSigAlgOID());
//        System.out.println("x509Certificate_getNotBefore_证书有效期__: " + x509Certificate.getNotAfter());
//        System.out.println("x509Certificate_getSigAlgName_签名算法__: " + x509Certificate.getSigAlgName());
//        System.out.println("x509Certificate_getVersion_版本号__: " + x509Certificate.getVersion());
//        System.out.println("x509Certificate_getPublicKey_公钥__: " + x509Certificate.getPublicKey());
//
//        System.out.println("\n\n");

        byte[] extensionValue = x509Certificate.getExtensionValue("1.2.3.4.5.6.7.8.1");

        // 重新解析json串
        StringBuilder builder = new StringBuilder();

        builder.append("{");

        String obj = new String(extensionValue);
        obj = obj.substring(obj.indexOf("{"));

        JSONObject jsonObject = JSON.parseObject(obj);
        Object attrsV = jsonObject.get("attrs");

        JSONObject jsonObject1 = JSON.parseObject(attrsV.toString());
        Set<Map.Entry<String, Object>> entries = jsonObject1.entrySet();
        for (Map.Entry<String, Object> key : entries){
            builder.append(",\"").append(key.getKey().replaceAll("\\.", "")).append("\":\"").append(key.getValue()).append("\"");
        }

        builder.append("}");

        obj = builder.toString().replaceFirst(",", "");

        this.attrs = JSON.parseObject(obj, Attrs.class);

        return this.attrs;
    }

}
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值