ACL权限
ZooKeeper的ACL可针对znodes设置相应的权限信息。
一个 ACL 权限设置通常可以分为 3 部分,分别是:权限模式(Scheme)、授权对象(ID)、权限信息(Permission)。
最终组成一条例如scheme:id:permission格式的 ACL 请求信息。
「权限模式:Scheme」
ZooKeeper 的权限验证方式大体分为两种类型,一种是范围验证,另外一种是口令验证。
❝
范围验证
❞
所谓的范围验证就是说 ZooKeeper 可以针对一个 IP 或者一段 IP 地址授予某种权限。
比如我们可以让一个 IP 地址为ip:192.168.0.11的机器对服务器上的某个数据节点具有写入的权限。
或者也可以通过ip:192.168.0.11/22给一段 IP 地址的机器赋权。
❝
口令验证
❞
可以理解为用户名密码的方式,这是我们最熟悉也是日常生活中经常使用的模式,比如我们打开自己的电脑或者去银行取钱都需要提供相应的密码。
在 ZooKeeper 中这种验证方式是 Digest 认证,我们知道通过网络传输相对来说并不安全,所以绝不通过明文在网络发送密码也是程序设计中很重要的原则之一,而 Digest 这种认证方式首先在客户端传送username:password这种形式的权限表示符后,ZooKeeper 服务端会对密码部分使用 SHA-1 和 BASE64 算法进行加密,以保证安全性。
❝
Super 权限模式
❞
权限模式 Super 可以认为是一种特殊的 Digest 认证。
具有 Super 权限的客户端可以对 ZooKeeper 上的任意数据节点进行任意操作。
下面这段代码给出了 Digest 模式下客户端的调用方式。
//创建节点
create /digest_node1
//设置digest权限验证
setAcl /digest_node1 digest:用户名:base64格式密码:rwadc
//查询节点Acl权限
getAcl /digest_node1
//授权操作
addauth digest user:passwd
❝
如果一个客户端对服务器上的一个节点设置了只有它自己才能操作的权限,那么等这个客户端下线或被删除后。
❞
对其创建的节点要想进行修改应该怎么做呢?
我们可以通过「super 模式」即超级管理员的方式删除该节点或变更该节点的权限验证方式。
正因为「super 模式」有如此大的权限,我们在平时使用时也应该更加谨慎。
❝
world 模式
❞
这种授权模式对应于系统中的所有用户,本质上起不到任何作用。
设置了 world 权限模式系统中的所有用户操作都可以不进行权限验证。
「授权对象(ID)」
所谓的授权对象就是说我们要把权限赋予谁,而对应于 4 种不同的权限模式来说,如果我们选择采用 IP 方式,使用的授权对象可以是一个 IP 地址或 IP 地址段;而如果使用 Digest 或 Super 方式,则对应于一个用户名。
如果是 World 模式,是授权系统中所有的用户。
「权限信息(Permission)」
权限就是指我们可以在数据节点上执行的操作种类,在 ZooKeeper 中已经定义好的权限有 5 种:
数据节点(create)创建权限,授予权限的对象可以在数据节点下创建子节点;
数据节点(wirte)更新权限,授予权限的对象可以更新该数据节点;
数据节点(read)读取权限,授予权限的对象可以读取该节点的内容以及子节点的信息;
数据节点(delete)删除权限,授予权限的对象可以删除该数据节点的子节点;
数据节点(admin)管理者权限,授予权限的对象可以对该数据节点体进行 ACL 权限设置。
❝
需要注意的一点是,每个节点都有维护自身的 ACL 权限数据,即使是该节点的子节点也是有自己的 ACL 权限而不是直接继承其父节点的权限。
❞
「实现自己的权限口控制」
虽然 ZooKeeper 自身的权限控制机制已经做得很细,但是它还是提供了一种权限扩展机制来让用户实现自己的权限控制方式。
官方文档中对这种机制的定义是 Pluggable ZooKeeper Authenication,意思是可插拔的授权机制,从名称上我们可以看出它的灵活性。那么这种机制是如何实现的呢?
❝
要想实现自定义的权限控制机制,最核心的一点是实现 ZooKeeper 提供的权限控制器接口 AuthenticationProvider。
❞
实现了自定义权限后,如何才能让 ZooKeeper 服务端使用自定义的权限验证方式呢?
接下来就需要将自定义的权限控制注册到 ZooKeeper 服务器中,而注册的方式通常有两种。
第一种是通过设置系统属性来注册自定义的权限控制器:
-Dzookeeper.authProvider.x=CustomAuthenticationProvider
另一种是在配置文件zoo.cfg中进行配置:
authProvider.x=CustomAuthenticationProvider
「实现原理」
首先是封装该请求的类型,之后将权限信息封装到 request 中并发送给服务端。而服务器的实现比较复杂,首先分析请求类型是否是权限相关操作,之后根据不同的权限模式(scheme)调用不同的实现类验证权限最后存储权限信息。
在授权接口中,值得注意的是会话的授权信息存储在 ZooKeeper 服务端的内存中,如果客户端会话关闭,授权信息会被删除。
下次连接服务器后,需要重新调用授权接口进行授权。
序列化方式
在 ZooKeeper 中并没有采用和 Java 一样的序列化方式,而是采用了一个 Jute 的序列解决方案作为 ZooKeeper 框架自身的序列化方式。
❝
ZooKeeper 从最开始就采用 Jute 作为其序列化解决方案,直到其最新的版本依然没有更改。
❞
虽然 ZooKeeper 一直将 Jute 框架作为序列化解决方案,但这并不意味着 Jute 相对其他框架性能更好,反倒是 Apache Avro、Thrift 等框架在性能上优于前者。
之所以 ZooKeeper 一直采用 Jute 作为序列化解决方案,主要是新老版本的兼容等问题。
「如何 使用 Jute 实现序列化」
如果我们要想将某个定义的类进行序列化,首先需要该类实现 Record 接口的 serilize 和 deserialize 方法,这两个方法分别是序列化和反序列化方法。
❝
下边这段代码给出了我们一般在 ZooKeeper 中进行序列化的具体实现:
❞
首先,我们定义了一个test_jute类,为了能够对它进行序列化,需要该test_jute类实现 Record 接口,并在对应的 serialize 序列化方法和 deserialize 反序列化方法中编辑具体的实现逻辑。
class test_jute implements Record{
private long ids;
private String name;
...
public void serialize(OutpurArchive a_,String tag){
...
}
public void deserialize(INputArchive a_,String tag){
...
}
}
在序列化方法 serialize 中,我们要实现的逻辑是,首先通过字符类型参数 tag 传递标记序列化标识符,之后使用 writeLong 和 writeString 等方法分别将对象属性字段进行序列化。
public void serialize(OutpurArchive a_,String tag) throws ...{
a_.startRecord(this.tag);
a_.writeLong(ids,"ids");
a_.writeString(type,"name");
a_.endRecord(this,tag);
}
调用 derseralize 在实现反序列化的过程则与我们上边说的序列化过程正好相反。
public void deserialize(INputArchive a_,String tag) throws {
a_.startRecord(tag);
ids = a_.readLong("ids");
name = a_.readString("name");
a_.endRecord(tag);
}
序列化和反序列化的实现逻辑编码方式相对固定,首先通过 startRecord 开启一段序列化操作,之后通过 writeLong、writeString 或 readLong、 readString 等方法执行序列化或反序列化。
本例中只是实现了长整型和字符型的序列化和反序列化操作,除此之外 ZooKeeper 中的 Jute 框架还支持整数类型(Int)、布尔类型(Bool)、双精度类型(Double)以及 Byte/Buffer 类型。
网友评论