ZooKeeper zk=new ZooKeeper("192.168.1.188,192.168.1.189,192.168.1.190",50000,w);
ArrayList<ACL> acls = new ArrayList<ACL>();
ACL acl1=new ACL(ZooDefs.Perms.ALL, new Id("digest", DigestAuthenticationProvider.generateDigest("qingxu:taobao123")));
//或者把以上两行换成如下三行
// zk.addAuthInfo("digest","qingxu:taobao123".getBytes());
//ArrayList<ACL> acls = new ArrayList<ACL>();
//ACL acl1=new ACL(ZooDefs.Perms.ALL, new Id("auth", ""));
acls.add(acl1);
zk.create("/qingxu/child",null, acls, CreateMode.PERSISTENT);
Thread.sleep(50000000); zk.close();
child这个znode对于用户qingxu来说具有所有权限。它采用的digest认证方式。
其他客户端如果要访问这个znode或者创建子znode,需要首先进行认证。
<pre class="java" name="code"><span style="font-size:18px;"> ZooKeeper zk=new ZooKeeper("192.168.1.188,192.168.1.189,192.168.1.190",50000,w);
zk.addAuthInfo<strong><span style="color:#ff0000;">("digest","qingxu:taobao123".</span></strong>getBytes());
zk.create("/qingxu/child/sunzi2",null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
zk.close();</span>
如果这里qingxu:taobao123输入成了qingxu:taobao124,那么将会抛出NoAuthException.
Zk 对znode操作采用ACL进行了访问权限控制,类似于linux提供的读写权限,ZK将操作权限划分以下几种:CREATE/READ/WRITE/DELETE/ADMIN,
· CREATE: 表示有权限创建一个子节点
· READ: 表示可以getData或者getChildren
· WRITE: 表示可以setData
· DELETE: 表示可以delete子节点
· ADMIN: 表示可以通过setACL设置znode权限
Create和delete权限是从write权限中拆分出来的,注意与linux中write的区别。ZK中使用常量类来标明了这些权限。
将这些权限与一系列Id进行关联就构成了节点的ACL控制对,可以这么看这个映射关系。
ACL=PermßàID
而ID由scheme和实际的字符串id组成。Scheme表示了与实际字符串id对应的认证scheme标识符,也就是说在对字符串id进行认证时,需要根据scheme找到对应的认证服务提供者来对id进行校验认证,例如Scheme=digest id=qingxu:pwd,表示digest关键字对应的认证服务提供者来对qingxu:pwd进行认证,
ZK提供了目前提供了基于客户端IP(scheme=ip)和基于摘要(SHA1,scheme=digest)用户密码的两种提供者, 他们都实现了AuthenticationProvider接口, 用户也可以通过设置以zookeeper.authProvider.开头的系统属性来增加其他用户自定义的授权方式(ProviderRegistry在初始化时会将自定义的授权方式加载进来)。在ZK服务端,授权Provider以HashMap的方式驻留在内存中,key是scheme,value是AuthenticationProvider接口的实现类,这样通过AuthenticationProvider getProvider(String scheme) 就可以得到具体的认证服务了。
在客户端准备创建znode时,create方法要求指定对本znode的ACL列表,标明:谁(id)采用某种认证方式(scheme)之后可以采取某种操作(perm).
public String create(final String path,byte data[], List<ACL> acl,
CreateMode createMode)
可以对一个znode使用多个ACL,当服务器端创建节点时会将这个ACL列表与该znode关联,并在随后某个时间持久化到snapshot中,当客户端对这个节点或者子节点进行操作时,会检查当前连接上来的客户端是否具有权限操作该节点,如果没有权限,就会抛出No Auth异常。对于有的权限认证信息,客户端不需要传递额外的信息给服务器,例如anyone,表示任何人,对于类似digest的认证服务,由于需要客户端提供用户密码,然后与服务端的用户密码进行校验(用户密码两者组合起来被认为是一个用户id),客户端输入认证服务的地方是通过通过客户端ZK的addAuthInfo(String scheme, byte auth[])方法添加对应认证信息(例如用户密码),这些认证信息会传递到服务器端做一些处理(主要是scheme服务器是否支持,对于scheme=digest主要是判定下是否super超级用户登录来了,scheme=ip就简单记录下当前登录ip),并保存在authinfo这个客户端列表中,以后这个连接就可以一直使用这个认证信息.
addAuthInfo 后的服务端流程如下:
服务器在节点进行权限检查时checkACL()流程如下:
Super用户直接通过,不进行任何权限(perm比较),可以进行任何操作。
否则,当前要进行的操作需要的权限perm与znode拥有的权限一致时,再比较用户。如果与znode上所有ACLperm都不一致,就表示没有通过校验,抛出NoAuthException异常。
如果该节点ACL是任何人都能访问(shceme=world 并且id=anyone),直接通过验证,否则,根据scheme找到认证服务provider,然后从authinfo中查找与该scheme相等同时id也match的ACL,找到则认证通过。如果所有的都没有验证通过,就抛出NoAuthException
最后:如果ZK服务器不想进行checkACL,那么服务器系统属性zookeeper.skipACL=yes即可。