org.apache.zookeeper.KeeperException$InvalidACLException: KeeperErrorCode = InvalidACL 节点操作权限问题

一、概述

节点不存在,正在创建…
Exception in thread "main" org.apache.zookeeper.KeeperException$InvalidACLException: KeeperErrorCode = InvalidACL for /succ/testdigest/childtest at org.apache.zookeeper.KeeperException.create(KeeperException.java:121)

 ACL :Access Control List 访问控制列表,用于控制资源的访问权限,类似于系统对文件的权限控制。

问题描述:

1、给用户lilei赋予节点“/succ/testdigest”的cdr操作权限;

2、通过前端代码登录lilei用户后,创建该节点的子节点时,提示上面的错误。

注:操作子节点时,首先要对父节点有操作权限,所以需要登录具有父节点操作权限的用户

问题根源:就是ACL的登录权限出问题了(要么没登录,要么登录没生效),别无他处。

解决办法:

1. 如果java客户端使用的原生态的zookeeper,尝试把登录代码紧挨着节点操作代码。 zookeeper.addAuthInfo("digest", "lilei:lilei".getBytes());//登录lilei用户

2.如果java客户端使用的是Curator,在实例化Client的时候,就需要登录有节点操作权限的用户。核心代码:.authorization("digest", "mayun:mayun".getBytes()) 

二、解决思路

1、关键字ACL,是权限问题。说明在操作某个节点时,权限存在不足。

2、脱离代码,难以说明问题,上代码!

三、我的代码片段(登录了,但是没生效)

1.创建节点的方法

  登录代码在这里才会生效,在main方法中不生效,很奇怪

public static void createNode(String nodePath,byte[]data,List<ACL> acls) throws Exception{
		ZooKeeper zookeeper=new ZKNodeAcl(zkServerPath).getZookeeper();
		Stat stat=zookeeper.exists(nodePath, false);//先判断节点是否已经存在(false意思是不再回调process)
		if(null!=stat) {
			System.out.println("节点已存在,版本号:"+stat.getVersion());
		}else {
			System.out.println("节点不存在,正在创建…");
			//zookeeper.addAuthInfo("digest", "lilei:lilei".getBytes());//登录lilei用户
			String result=zookeeper.create(nodePath, data, acls,CreateMode.PERSISTENT);
			System.out.println("创建节点:\t"+result+"\t成功");
		}
	}

注:zookeeper.addAuthInfo("digest", "lilei:lilei".getBytes());//登录lilei用户

这段代码稍后要放开,也就是说不要在main方法中登录(登录不会生效),在节点操作方法的上一行代码登录。 

2.单独赋予用户权限方法,返回用户权限ACLs列表

//同一个节点,分别给mayun和lilei两个用户分配不同的操作权限
	public static List<ACL> getAcls() throws NoSuchAlgorithmException{
		List<ACL> acls=new ArrayList<ACL>();
		Id mayun =new Id("digest", AclUtils.getDigestUserPwd("mayun:mayun"));
		Id lilei =new Id("digest", AclUtils.getDigestUserPwd("lilei:lilei"));
		acls.add(new ACL(Perms.ALL, mayun));//给mayun一次性赋值所有权限
		acls.add(new ACL(Perms.READ, lilei));
		acls.add(new ACL(Perms.DELETE | Perms.CREATE, lilei));//给lilei分两次赋权限(目的:看不同的赋权方式)
		return acls;
	}

3.main方法(问题所在,发现登录代码在这里没生效)

   public static void main(String[] args) throws Exception {
		ZKNodeAcl zkServer=new ZKNodeAcl(zkServerPath);
		//ZKNodeAcl.createNode("/succ/abc", "hello".getBytes(), Ids.OPEN_ACL_UNSAFE);//分配所有权限
		//ZKNodeAcl.createNode("/succ/testdigest", "testdigest".getBytes(), getAcls());//分配自定义权限
		//succ/testdigest节点已创建且已分配权限,如果要对这个节点操作,则需要先登录
		zkServer.getZookeeper().addAuthInfo("digest", "lilei:lilei".getBytes());//登录lilei用户(就是这个行代码,感觉是没有生效)
		zkServer.createNode("/succ/testdigest/childtest", "childtest".getBytes(), Ids.CREATOR_ALL_ACL);//赋予lilei对子节点所有权限
   	}
	

四、解决步骤

1.诡异的权限登录,明明在main中登录了,还是报错提示ACL权限问题

因在main方法中上一步操作,创建“/succ/testdigest”节点时,在getAcls()方法中给用户lilei分配了这个节点的cdr权限。

然而,需要给“/succ/testdigest”这个节点,创建子节点时,创建子节点前必须先登录具有该节点操作权限的用户。zk 后台代码是 #addauth digest lilei:lilei ,这段代码转换为前台代码就是:

zkServer.getZookeeper().addAuthInfo("digest", "lilei:lilei".getBytes()); 

如上代码,明明是已经登录了,还是报错。一顿度娘,无果,索性就把登录代码转移到创建节点代码的上一行,让创建子节点的代码与权限登录代码挨着

2.权限登录让其紧挨着创建子节点的代码

zookeeper.addAuthInfo("digest", "lilei:lilei".getBytes());//登录lilei用户
			String result=zookeeper.create(nodePath, data, acls,CreateMode.PERSISTENT);

再次运行,发现子节点操作成功了。

结论

登录代码和节点操作代码,如果不在一个方法中,会不生效,不确定是bug还是什么原因。

本案例中,登录代码在main方法中,通过main方法调用子节点创建方法createNode(),然后诡异的是,登录没能生效。把登录代码,转移到createNode()方法内部,就生效了。

 如果你的问题没有被解决,且客户端使用的是Curator继续看如下代码

这是一个类的构造方法,在代码中添加:.authorization("digest", "mayun:mayun".getBytes()),里面的mayun:mayun需要替换为你本地创建的具有操作权限的用户名和密码

public CuratorAcl() {
        RetryPolicy retryPolicy = new RetryNTimes(3, 5000);
        client = CuratorFrameworkFactory.builder().authorization("digest", "mayun:mayun".getBytes())
                .connectString(zkServerPath)
                .sessionTimeoutMs(10000).retryPolicy(retryPolicy)
                .namespace("workspace").build();
        client.start();
    }

需要注意的是:这个行代码,还有一个兄弟方法,可以一次性登录多个用户。 

尾言 

本案例不知可否解决你遇到的问题,但是希望能为你提供一种解决问题的思路。总之遇到这个问题,就是ACL权限问题。登录代码是少不了的,基本是出现了登录代码这个点。

如果找不到解决思路,先排查自己是否具有该节点的操作权限吧,比如:

#getAcl /succ/testDigest 查看都有哪些用户对该节点有操作权限,然后据上述代码登录后,再对节点进行操作。

附录:AclUtils.java

import java.security.NoSuchAlgorithmException;

import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;

public class AclUtils {
	public static String getDigestUserPwd(String idPassword) throws NoSuchAlgorithmException {
		return DigestAuthenticationProvider.generateDigest(idPassword);
	}
	public static void main(String[] args) throws NoSuchAlgorithmException {
		String idPassword="succ:succ";//该用户通过后台的#addauth digested succ:succ 命令来创建的
		String idDigested=getDigestUserPwd(idPassword);
		System.out.println(idDigested);
		//succ:xwbPSQtEd/X8NWYNr6QOFbTnJ3A=
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
org.apache.zookeeper.KeeperException$ConnectionLossExceptionZooKeeper客户端库中的一个异常类,表示与ZooKeeper服务器的连接丢失。这个异常通常在以下情况下抛出: 1. 当客户端与ZooKeeper服务器的连接意外断开时,会抛出ConnectionLossException异常。 2. 当客户端尝试与ZooKeeper服务器建立连接时,如果连接失败,也会抛出ConnectionLossException异常。 这个异常类的完整名称是org.apache.zookeeper.KeeperException$ConnectionLossException,它是KeeperException的一个子类。KeeperExceptionZooKeeper客户端库中的一个通用异常类,用于表示与ZooKeeper服务器交互过程中的各种错误。 在处理ConnectionLossException异常时,可以采取以下措施: 1. 检查网络连接:首先,确保客户端与ZooKeeper服务器之间的网络连接是正常的。可以尝试ping ZooKeeper服务器的IP地址,以确保网络连接没有问题。 2. 重试操作:如果连接丢失是由于网络问题导致的,可以尝试重新连接并重试之前的操作。可以使用重试机制来处理ConnectionLossException异常,例如使用循环和延迟重试策略。 3. 检查ZooKeeper服务器状态:如果连接丢失是由于ZooKeeper服务器本身的问题导致的,可以检查ZooKeeper服务器的状态。可以查看ZooKeeper服务器的日志文件,以了解是否有任何错误或异常发生。 4. 调整ZooKeeper客户端配置:有时,连接丢失问题可能是由于ZooKeeper客户端配置不正确导致的。可以检查ZooKeeper客户端的配置文件,确保配置正确。 总之,org.apache.zookeeper.KeeperException$ConnectionLossException表示与ZooKeeper服务器的连接丢失,可以通过检查网络连接、重试操作、检查ZooKeeper服务器状态和调整ZooKeeper客户端配置来处理这个异常。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值