一:Zookeeper权限控制
????? 在zk集群中,不同的应用之间一般不会存在共享数据,为了避免某一个数据被不同的进程修改,这就需要进行相应的权限控制。
二:ACL介绍
??????? Zookeeper使用ACL机制来实现权限的控制,ACL机制主要分为3个方面,权限模式,权限ID和权限。
? 2.1 权限模式
?(1)IP
? ip模式是指权限针对这个ip而设置的,比如"ip:192.168.0.00",即允许这个ip方法数据节点。
?(2)digest
? digest模式是最常用的一种模式,形如"username:password"的方式。设置成digest模式后,zk会使用如下的方式进行加密:
?public static void main(String[] args) {
?? try {???
?? ? System.out.println(DigestAuthenticationProvider
????? .generateDigest("tanjie:123"));
??? } catch (NoSuchAlgorithmException e) {
??? ?? e.printStackTrace();
??? }
?? }
?结果:
? tanjie:Q7FWxEJF7trsn2KKyWNOf1yqbKs=
?3)World
? World模式其实是一种开放的模式,即对所以用户开放,形如"world:anyone",事实上这种模式没什么效果,因为设置了也对所有人开放。
?4)Super
? Super模式是超级管理员模式,超级管理员可以对任何节点进行操作,想象一下,如果创建某个持久节点的进程已经不再使用了,那这个持久的节点该怎么处理呢,这就需要使用超级管理员模式了,要使用超级管理员模式,需要在zk的启动脚本zkServer.sh里面配置一下,可以配置如"super:password",其中super是用户名,password是密码,这个可以根据需要随便设置。
? 配置完成后,然后重启zkServer即可,然后在你的程序中,就可以以超级管理员的方法给zk客户端添加权限然后就可以访问任何节点了。
?2.2 授权对象ID
? zk的授权对象是指将权限赋予谁,比如ip就是赋予一个ip地址,digest形式就是服务指定的用户名,super模式就是超级管理员,world默认就是anyone。
?2.3 权限
? 权限就是通过设置被允许的操作,常见的就是CRUD和ADMIN。
三:举例说明
??????? 通过上面的介绍,大家已经对zk的ACL权限是如何控制对节点数据的访问,下面通过一些例子来加深认识。
例一:不同的客户端去获取设置了权限的同一个节点的数据
public class Zookeeper_Acl_Create implements Watcher {
? private static CountDownLatch latch = new CountDownLatch(1);
? private static CountDownLatch countDownLatch = new CountDownLatch(1);
? private static ZooKeeper zk = null;
? public void syncInit() {
?try {
?? zk = new ZooKeeper(CONNECTION_IP, 5000, new Zookeeper_Acl_Create());
?? latch.await();
?? zk.addAuthInfo("digest", "username:password".getBytes());
?? zk.create("/act", "init".getBytes(), Ids.CREATOR_ALL_ACL,????? CreateMode.EPHEMERAL);
?? ZooKeeper zk3 = new ZooKeeper(CONNECTION_IP, 5000,null));
?? zk3.addAuthInfo("digest","username:password".getBytes());
?? String value2 = new String(zk3.getData("/act", false, null));
?? System.out.println("zk3有权限进行数据的获取" + value2);
?? ZooKeeper zk2 = new ZooKeeper(CONNECTION_IP, 5000,null);
?? zk2.addAuthInfo("digest", "super:123".getBytes());
?? zk2.getData("/act", false, null);
? }catch(InterruptedException e) {
??? e.printStackTrace();
? }catch(IOException e) {
??? e.printStackTrace();
? } catch (KeeperException e) {
??? System.out.println("异常:" + e.getMessage());
??? System.out.println("zk2没有权限进行数据的取");
??? countDownLatch.countDown();
?? }
? }
? @Override
? public void process(WatchedEvent event) {
?? if (KeeperState.SyncConnected == event.getState()) {
???? if (event.getType() == EventType.None && null ==event.getPath()){
??? ??? latch.countDown();
??? ? }
?? }
?}
?public static void main(String[] args){
?? Zookeeper_Acl_Create acl_Create = new Zookeeper_Acl_Create();
?? acl_Create.syncInit();
?? countDownLatch.await();
? }
}
运行结果如下:
? zk3有权限进行数据的获取init
? 异常:KeeperErrorCode = NoAuth for /act
? zk2没有权限进行数据的获取
可以看到,路径"/act"我们使用digest模式添加了权限,zk3使用正确的用户名密码进行节点访问可以获取到节点数据,但是zk2使用了错误的权限,zk就会报错。
例二:删除节点权限特殊说明
? 对于节点的删除,如果一个节点存在其子节点,需要注意的是,权限是不能被继承的.看下面的程序
public final class Zookeeper_Acl_delete implements Watcher {
?? private static CountDownLatch latch = new CountDownLatch(1);
?? private static CountDownLatch countDownLatch = new CountDownLatch(1);
?? private static ZooKeeper zk = null;
?? private static ZooKeeper zk2 = null;
?? private static ZooKeeper zk3 = null;
?? private static ZooKeeper zk4 = null;
?? final static String PATH = "/acl-delete";
?? final static String PATH2 = "/acl-delete/child";
?? public static void syncInit() {
?? try {
? ? ? ? zk = new ZooKeeper("ip:2181", 5000, new Zookeeper_Acl_delete());
?????? latch.await();
?????? zk.addAuthInfo("digest", "true".getBytes());
?????? zk.create(PATH, "init".getBytes(), Ids.CREATOR_ALL_ACL,
??? ??? ??? ? CreateMode.PERSISTENT);
? ? ? ? zk.create(PATH2, "init".getBytes(), Ids.CREATOR_ALL_ACL,
??? ??? ??? ? CreateMode.EPHEMERAL);
? ? ? ? zk2 = new ZooKeeper("ip:2181", 5000,null);
? ??? try{
??? ? ?? zk2.delete(PATH2, -1);
??? ? ? }catch(Exception e){
??? ???? System.out.println("异常:" + e.getMessage());
?? ? ? }
? ? ? zk3 = new ZooKeeper("ip:2181",5000, null);
???? zk3.addAuthInfo("digest", "true".getBytes());
???? zk3.delete(PATH2, -1);
???? System.out.println("删除节点成功:" + PATH2);
???? zk4 = new ZooKeeper("ip:2181", 5000,null);
???? zk4.delete(PATH, -1);
???? System.out.println("删除节点成功:" + PATH);
? ?? countDownLatch.countDown();
?? } catch (Exception e) {
?? ?? System.out.println("异常:" + e.getMessage());
?? }
}
? @Override
? public void process(WatchedEvent event) {
?? if (KeeperState.SyncConnected == event.getState()) {
??? if (event.getType() == EventType.None && null ==event.getPath()){
??? ??? latch.countDown();
???? }
?? }
?}
? public static void main(String[] args){
???? syncInit();
???? countDownLatch.await();
? }
}
运行结果如下:
? 异常:KeeperErrorCode = NoAuth for /acl-delete/child
? 删除节点成功:/acl-delete/child
? 删除节点成功:/acl-delete
? 可以看到,第一次我们使用无权限的zk2去删除,显然会报错,第二次我们使用带权限的zk3去操作,子节点被删除成功,但是当我们使用zk4去执行删除操作的时候并没有指定任何权限,依然能够删除其父节点,说明zk在进行删除操作的时候,其权限的作用范围是其子节点。也就是说,当我们对一个节点添加了权限之后我们依然可以随意删除该节点但是对于这个节点的子节点,就必须拥有相应的权限才能删除。而且zk原生api不支持递归删除即在存在子节点的情况下,不允许删除其父节点。
原文:http://tanjie090508.iteye.com/blog/2287926