默认匿名权限
ZooKeeper提供了如下几种验证模式(scheme):
digest:Client端由用户名和密码验证,譬如user:password,digest的密码生成方式是Sha1摘要的base64形式
auth:不使用任何id,代表任何已确认用户。
ip:Client端由IP地址验证,譬如172.2.0.0/24
world:固定用户为anyone,为所有Client端开放权限
super:在这种scheme情况下,对应的id拥有超级权限,可以做任何事情(cdrwa)
注意的是,exists操作和getAcl操作并不受ACL许可控制,因此任何客户端可以查询节点的状态和节点的ACL。
节点的权限(perms)主要有以下几种:
Create 允许对子节点Create操作
Read 允许对本节点GetChildren和GetData操作
Write 允许对本节点SetData操作
Delete 允许对子节点Delete操作
Admin 允许对本节点setAcl操作
Znode ACL权限用一个int型的十进制数字perms表示,perms的5个二进制位分别表示setacl、delete、create、write、read。比如0x1f=adcwr,0x1=----r,0x15=a-c-r。
以下示例在创建节点的时候,赋予该节点的权限为默认匿名权限,权限位为adcwr,换成十进制数字表示就是3
1,十六进制则是0x1f。代码如下:
package org.zero01.zk.demo;import org.apache.zookeeper.*;import org.apache.zookeeper.data.ACL;import org.apache.zookeeper.data.Stat;import java.util.List;/** * @program: zookeeper-connection * @description: zookeeper 操作节点acl权限演示 * @author: 01 * @create: 2018-04-27 09:20 **/public class ZKNodeAcl implements Watcher { // 集群模式则是多个ip private static final String zkServerIps = "192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181"; // 超时时间 private static final Integer timeout = 5000; private static ZooKeeper zooKeeper; private static Stat stat; // Watch事件通知方法 public void process(WatchedEvent watchedEvent) { } public static void main(String[] args) throws Exception { zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKNodeAcl()); // 这样创建的节点是默认匿名权限的:ZooDefs.Ids.OPEN_ACL_UNSAFE String result = zooKeeper.create("/testAclNode", "test data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); Thread.sleep(1000); // 获取该节点的acl权限信息 List<ACL> aclList = zooKeeper.getACL("/testAclNode", stat); for (ACL acl : aclList) { System.out.println("权限scheme id:" + acl.getId()); // 获取的是十进制的int型数字 System.out.println("权限位:" + acl.getPerms()); } // 避免与服务端的连接马上断开 Thread.sleep(1000); }}
控制台输出内容如下:
权限scheme id:'world,'anyone权限位:31
ZooDefs.Ids可以直接使用的权限如下:
ZooDefs.Ids.OPEN_ACL_UNSAFE // 默认匿名权限,权限scheme id:'world,'anyone,权限位:31(adcwr)ZooDefs.Ids.READ_ACL_UNSAFE // 只读权限,权限scheme id:'world,'anyone,权限位:1(r)
自定义用户权限
本节介绍如何自定义用户权限,这里使用digest进行演示,因为平时工作中digest是用得最多的。我们都知道digest是使用密文进行设置的,所以我们需要自定义一个工具类来加密明文密码得到密文密码。代码如下:
package org.zero01.zk.util;import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;public class AclUtils { public static String getDigestUserPwd(String id) throws Exception { // 加密明文密码 return DigestAuthenticationProvider.generateDigest(id); }}
然后修改 ZKNodeAcl 类的代码如下:
package org.zero01.zk.demo;import org.apache.zookeeper.*;import org.apache.zookeeper.data.ACL;import org.apache.zookeeper.data.Id;import org.apache.zookeeper.data.Stat;import org.zero01.zk.util.AclUtils;import java.util.ArrayList;import java.util.List;/** * @program: zookeeper-connection * @description: zookeeper 操作节点acl权限演示 * @author: 01 * @create: 2018-04-27 09:20 **/public class ZKNodeAcl implements Watcher { // 集群模式则是多个ip private static final String zkServerIps = "192.168.190.128:2181,192.168.190.129:2181,192.168.190.130:2181"; // 超时时间 private static final Integer timeout = 5000; private static ZooKeeper zooKeeper; private static Stat stat; public void process(WatchedEvent watchedEvent) { } public static void main(String[] args) throws Exception { zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKNodeAcl()); // 自定义用户认证访问 List<ACL> acls = new ArrayList<ACL>(); // 权限列表 // 第一个参数是权限scheme,第二个参数是加密后的用户名和密码 Id user1 = new Id("digest", AclUtils.getDigestUserPwd("user1:123456a")); Id user2 = new Id("digest", AclUtils.getDigestUserPwd("user2:123456b")); acls.add(new ACL(ZooDefs.Perms.ALL, user1)); // 给予所有权限 acls.add(new ACL(ZooDefs.Perms.READ, user2)); // 只给予读权限 acls.add(new ACL(ZooDefs.Perms.DELETE | ZooDefs.Perms.CREATE, user2)); // 多个权限的给予方式,使用 | 位运算符 // 使用自定义的权限列表去创建节点 String result = zooKeeper.create("/testDigestNode", "test data".getBytes(), acls, CreateMode.PERSISTENT); if (result != null) { System.out.println("创建节点:\t" + result + "\t成功..."); } Thread.sleep(1000); // 获取该节点的acl权限信息 List<ACL> aclList = zooKeeper.getACL("/testDigestNode", stat); for (ACL acl : aclList) { System.out.println("\n-----------------------\n"); System.out.println("权限scheme id:" + acl.getId()); System.out.println("权限位:" + acl.getPerms()); } Thread.sleep(1000); }}
控制台输出信息如下:
创建节点: /testDigestNode 成功...-----------------------权限scheme id:'digest,'user1:TQYTqd46qVVbWpOd02tLO5qb+JM=权限位:31-----------------------权限scheme id:'digest,'user2:CV4ED0rE6SxA3h/DN/WyScDMbCs=权限位:1-----------------------权限scheme id:'digest,'user2:CV4ED0rE6SxA3h/DN/WyScDMbCs=权限位:12
我们可以到服务器上查看该节点的ACL信息是否一致:
[zk: localhost:2181(CONNECTED) 15] getAcl /testDigestNode'digest,'user1:TQYTqd46qVVbWpOd02tLO5qb+JM=: cdrwa'digest,'user2:CV4ED0rE6SxA3h/DN/WyScDMbCs=: r'digest,'user2:CV4ED0rE6SxA3h/DN/WyScDMbCs=: cd[zk: localhost:2181(CONNECTED) 16]
如果我们需要操作一个设置了digest权限的节点,那么就需要登录用于相应权限的用户才行。在代码上也是如此,我们需要先通过addAuthInfo添加用户信息(账户:明文密码)才能够操作其拥有权限的节点。以下示例演示如何使用addAuthInfo添加用户信息并操作相应的节点,修改main方法的代码如下:
...public class ZKNodeAcl implements Watcher { ... public static void main(String[] args) throws Exception { zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKNodeAcl()); // 注册过的用户必须通过addAuthInfo才能操作节点,参考命令行 addauth zooKeeper.addAuthInfo("digest", "user1:123456a".getBytes()); String result = zooKeeper.create("/testDigestNode/testOneNode", "test data".getBytes(), ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT); if (result != null) { System.out.println("创建子节点:\t" + result + "\t成功..."); } // 获取节点数据 byte[] data = zooKeeper.getData("/testDigestNode/testOneNode", false, stat); System.out.println(new String(data)); // 设置节点数据 zooKeeper.setData("/testDigestNode/testOneNode", "new test data".getBytes(), 0); Thread.sleep(1000); }}
控制台输出信息如下:
创建子节点: /testDigestNode/testOneNode 成功...test data
ip权限
以上我们简单演示了默认匿名权限以及自定义的digest权限,下面简单演示下自定义ip权限的设置方式。修改 ZKNodeAcl 类中的main方法代码如下:
...public class ZKNodeAcl implements Watcher { ... public static void main(String[] args) throws Exception { zooKeeper = new ZooKeeper(zkServerIps, timeout, new ZKNodeAcl()); // ip方式的acl List<ACL> aclsIP = new ArrayList<ACL>(); // 权限列表 // 第一个参数是权限scheme,第二个参数是ip地址 Id ipId1 = new Id("ip", "192.168.190.1"); aclsIP.add(new ACL(ZooDefs.Perms.ALL, ipId1)); // 给予所有权限 // 使用自定义的权限列表去创建节点 String result = zooKeeper.create("/testIpNode", "this is test ip node data".getBytes(), aclsIP, CreateMode.PERSISTENT); if (result != null) { System.out.println("创建节点:\t" + result + "\t成功..."); } Thread.sleep(1000); // 获取该节点的acl权限信息 List<ACL> aclList = zooKeeper.getACL(result, stat); for (ACL acl : aclList) { System.out.println("\n-----------------------\n"); System.out.println("权限scheme id:" + acl.getId()); System.out.println("权限位:" + acl.getPerms()); } Thread.sleep(1000); // 获取节点数据,验证ip是否有权限 byte[] data = zooKeeper.getData("/testIpNode", false, stat); System.out.println("\n-----------------------\n"); System.out.println(result + " 节点当前的数据为:" + new String(data)); }}
控制台输出信息如下:
创建节点: /testIpNode 成功...-----------------------权限scheme id:'ip,'192.168.190.1权限位:31-----------------------/testIpNode 节点当前的数据为:this is test ip node data