zoukankan      html  css  js  c++  java
  • ZooKeeper 权限管理

    这其中一个显而易见的问题就是权限:如果我的数据被别人动了怎么办?


    方案一:采用ZooKeeper支持的ACL digest方式,用户自己定义节点的权限

            这种方案将zookeeper的acl和digest授权认证模式相结合。具体操作流程如下:

           

          可以把这个访问授权过程看作是用户注册,系统给你一个密码,每次操作使用这个用户名(appName)和密码. 于是就可以对应有这样权限管理系统,专门是负责进行节点的创建申请:包含“申请私有节点”和“申请公有节点”。这样一来,节点的创建都是由这个权限管理系统来负责了,每次申请完后,系统都会返回给你的一个key,格式通常是“{appName}:{password}”,以后你的任何操作都要在zk session 中携带上这个key,这样就能进行权限控制。当然,用户自己通过zk客户端进行path的创建也是可以的,只是要求他们要使用授权方式来进行zk节点的创建。(注意,如果使用zkclient,请使用 https://github.com/nileader/zkclient )

    整个权限控制流程的代码测试,如下图所示,点击查看大图:(测试代码在这里


    1. package org.I0Itec.zkclient; 
    2.  
    3. import java.util.ArrayList; 
    4. import java.util.List; 
    5.  
    6. import org.apache.zookeeper.WatchedEvent; 
    7. import org.apache.zookeeper.Watcher; 
    8. import org.apache.zookeeper.ZooDefs.Ids; 
    9. import org.apache.zookeeper.data.ACL; 
    10.  
    11. /** 
    12. * Description: ZooKeepre ACL权限控制 测试 
    13. * @author nileader / nileader@gmail.com 
    14. * @Date Feb 2, 2012 
    15. */ 
    16. public class DemoAuth implements Watcher { 
    17.  
    18. final static String SERVER_LIST = “127.0.0.1:4711″; 
    19.  
    20. final static String PATH = “/yinshi_auth_test”; 
    21. final static String PATH_DEL = “/yinshi_auth_test/will_be_del”; 
    22.  
    23. final static String authentication_type = “digest”; 
    24.  
    25. final static String correctAuthentication = “taokeeper:true”; 
    26. final static String badAuthentication = “taokeeper:errorCode”; 
    27.  
    28. static ZkClient zkClient = null
    29.  
    30. public static void main( String[] args ) throws Exception { 
    31.  
    32. List< ACL > acls = new ArrayList< ACL >( 1 ); 
    33. for ( ACL ids_acl : Ids.CREATOR_ALL_ACL ) { 
    34. acls.add( ids_acl ); 
    35.  
    36. try { 
    37. zkClient = new ZkClient( SERVER_LIST, 50000); 
    38. zkClient.addAuthInfo( authentication_type, correctAuthentication.getBytes() ); 
    39. catch ( Exception e ) { 
    40. // TODO Auto-generated catch block 
    41. e.printStackTrace(); 
    42.  
    43. try { 
    44. zkClient.createPersistent( PATH, acls, “init content” ); 
    45. System.out.println( “使用授权key:” + correctAuthentication + “创建节点:” + PATH + “, 初始内容是: init content” ); 
    46. catch ( Exception e ) { 
    47. e.printStackTrace(); 
    48. try { 
    49. zkClient.createPersistent( PATH_DEL, acls, “待删节点” ); 
    50. System.out.println( “使用授权key:” + correctAuthentication + “创建节点:” + PATH_DEL + “, 初始内容是: init content” ); 
    51. catch ( Exception e ) { 
    52. // TODO Auto-generated catch block 
    53. e.printStackTrace(); 
    54.  
    55. // 获取数据 
    56. getDataByNoAuthentication(); 
    57. getDataByBadAuthentication(); 
    58. getDataByCorrectAuthentication(); 
    59.  
    60. // 更新数据 
    61. updateDataByNoAuthentication(); 
    62. updateDataByBadAuthentication(); 
    63. updateDataByCorrectAuthentication(); 
    64.  
    65. // 获取数据 
    66. getDataByNoAuthentication(); 
    67. getDataByBadAuthentication(); 
    68. getDataByCorrectAuthentication(); 
    69.  
    70. //删除数据 
    71. deleteNodeByBadAuthentication(); 
    72. deleteNodeByNoAuthentication(); 
    73. deleteNodeByCorrectAuthentication(); 
    74.  
    75. deleteParent(); 
    76.  
    77. zkClient.close(); 
    78.  
    79. /** 获取数据:采用错误的密码 */ 
    80. static void getDataByBadAuthentication() { 
    81. String prefix = “[使用错误的授权信息]“; 
    82. try { 
    83. System.out.println( prefix + “获取数据:” + PATH ); 
    84. zkClient = new ZkClient( SERVER_LIST, 50000); 
    85. zkClient.addAuthInfo( authentication_type, badAuthentication.getBytes() ); 
    86. System.out.println( prefix + “成功获取数据:” + zkClient.readData( PATH ) ); 
    87. catch ( Exception e ) { 
    88. System.err.println( prefix + “获取数据失败,原因:” + e.getMessage() ); 
    89.  
    90. /** 获取数据:不采用密码 */ 
    91. static void getDataByNoAuthentication() { 
    92. String prefix = “[不使用任何授权信息]“; 
    93. try { 
    94. System.out.println( prefix + “获取数据:” + PATH ); 
    95. zkClient = new ZkClient( SERVER_LIST, 50000); 
    96. System.out.println( prefix + “成功获取数据:” + zkClient.readData( PATH ) ); 
    97. catch ( Exception e ) { 
    98. System.err.println( prefix + “获取数据失败,原因:” + e.getMessage() ); 
    99.  
    100. /** 采用正确的密码 */ 
    101. static void getDataByCorrectAuthentication() { 
    102. String prefix = “[使用正确的授权信息]“; 
    103. try { 
    104. System.out.println( prefix + “获取数据:” + PATH ); 
    105. zkClient = new ZkClient( SERVER_LIST, 50000); 
    106. zkClient.addAuthInfo( authentication_type, correctAuthentication.getBytes() ); 
    107. System.out.println( prefix + “成功获取数据:” + zkClient.readData( PATH ) ); 
    108. catch ( Exception e ) { 
    109. System.out.println( prefix + “获取数据失败,原因:” + e.getMessage() ); 
    110.  
    111. /** 
    112. * 更新数据:不采用密码 
    113. */ 
    114. static void updateDataByNoAuthentication() { 
    115.  
    116. String prefix = “[不使用任何授权信息]“; 
    117.  
    118. System.out.println( prefix + “更新数据: ” + PATH ); 
    119. try { 
    120. zkClient = new ZkClient( SERVER_LIST, 50000); 
    121. if( zkClient.exists( PATH ) ){ 
    122. zkClient.writeData( PATH, prefix ); 
    123. System.out.println( prefix + “更新成功” ); 
    124. catch ( Exception e ) { 
    125. System.err.println( prefix + “更新失败,原因是:” + e.getMessage() ); 
    126.  
    127. /** 
    128. * 更新数据:采用错误的密码 
    129. */ 
    130. static void updateDataByBadAuthentication() { 
    131.  
    132. String prefix = “[使用错误的授权信息]“; 
    133.  
    134. System.out.println( prefix + “更新数据:” + PATH ); 
    135. try { 
    136. zkClient = new ZkClient( SERVER_LIST, 50000); 
    137. zkClient.addAuthInfo( authentication_type, badAuthentication.getBytes() ); 
    138. if( zkClient.exists( PATH ) ){ 
    139. zkClient.writeData( PATH, prefix ); 
    140. System.out.println( prefix + “更新成功” ); 
    141. catch ( Exception e ) { 
    142. System.err.println( prefix + “更新失败,原因是:” + e.getMessage() ); 
    143.  
    144. /** 
    145. * 更新数据:采用正确的密码 
    146. */ 
    147. static void updateDataByCorrectAuthentication() { 
    148.  
    149. String prefix = “[使用正确的授权信息]“; 
    150.  
    151. System.out.println( prefix + “更新数据:” + PATH ); 
    152. try { 
    153. zkClient = new ZkClient( SERVER_LIST, 50000); 
    154. zkClient.addAuthInfo( authentication_type, correctAuthentication.getBytes() ); 
    155. if( zkClient.exists( PATH ) ){ 
    156. zkClient.writeData( PATH, prefix ); 
    157. System.out.println( prefix + “更新成功” ); 
    158. catch ( Exception e ) { 
    159. System.err.println( prefix + “更新失败,原因是:” + e.getMessage() ); 
    160.  
    161. /** 
    162. * 不使用密码 删除节点 
    163. */ 
    164. static void deleteNodeByNoAuthentication() throws Exception { 
    165.  
    166. String prefix = “[不使用任何授权信息]“; 
    167.  
    168. try { 
    169. System.out.println( prefix + “删除节点:” + PATH_DEL ); 
    170. zkClient = new ZkClient( SERVER_LIST, 50000); 
    171. if( zkClient.exists( PATH_DEL ) ){ 
    172. zkClient.delete( PATH_DEL ); 
    173. System.out.println( prefix + “删除成功” ); 
    174. catch ( Exception e ) { 
    175. System.err.println( prefix + “删除失败,原因是:” + e.getMessage() ); 
    176.  
    177. /** 
    178. * 采用错误的密码删除节点 
    179. */ 
    180. static void deleteNodeByBadAuthentication() throws Exception { 
    181.  
    182. String prefix = “[使用错误的授权信息]“; 
    183.  
    184. try { 
    185. System.out.println( prefix + “删除节点:” + PATH_DEL ); 
    186. zkClient = new ZkClient( SERVER_LIST, 50000); 
    187. zkClient.addAuthInfo( authentication_type, badAuthentication.getBytes() ); 
    188. if( zkClient.exists( PATH_DEL ) ){ 
    189. zkClient.delete( PATH_DEL ); 
    190. System.out.println( prefix + “删除成功” ); 
    191. catch ( Exception e ) { 
    192. System.err.println( prefix + “删除失败,原因是:” + e.getMessage() ); 
    193.  
    194. /** 
    195. * 使用正确的密码删除节点 
    196. */ 
    197. static void deleteNodeByCorrectAuthentication() throws Exception { 
    198.  
    199. String prefix = “[使用正确的授权信息]“; 
    200.  
    201. try { 
    202. System.out.println( prefix + “删除节点:” + PATH_DEL ); 
    203. zkClient = new ZkClient( SERVER_LIST, 50000); 
    204. zkClient.addAuthInfo( authentication_type, correctAuthentication.getBytes() ); 
    205. if( zkClient.exists( PATH_DEL ) ){ 
    206. zkClient.delete( PATH_DEL ); 
    207. System.out.println( prefix + “删除成功” ); 
    208. catch ( Exception e ) { 
    209. System.out.println( prefix + “删除失败,原因是:” + e.getMessage() ); 
    210.  
    211. /** 
    212. * 使用正确的密码删除节点 
    213. */ 
    214. static void deleteParent() throws Exception { 
    215. try { 
    216. zkClient = new ZkClient( SERVER_LIST, 50000); 
    217. zkClient.addAuthInfo( authentication_type, correctAuthentication.getBytes() ); 
    218. if( zkClient.exists( PATH ) ){ 
    219. zkClient.delete( PATH ); 
    220. catch ( Exception e ) { 
    221. e.printStackTrace(); 
    222.  
    223. @Override 
    224. public void process( WatchedEvent event ) { 
    225. // TODO Auto-generated method stub 
    226.  
    227.  

     

    方案二、对zookeeper的AuthenticationProvider进行扩展,和内部其它系统A打通,从系统A中获取一些信息来判断权限

    这个方案大致是这样:
    1. A系统上有一份IP和appName对应的数据本地。
    2. 将这份数据在ZK服务器上缓存一份,并定时进行缓存更新。
    3. 每次客户端对服务器发起请求的时候,获取客户端ip进行查询,判断是否有对应appName的权限。限制指定ip只能操作指定 /appName znode。
    4. 其它容灾措施。

    个人比较两个方案:
    1.方案一较方案二,用户的掌控性大,无论线上,日常,测试都可以由应用开发人员自己决定开启/关闭权限。 (方案一的优势)
    2.方案二较方案一,易用性强,用户的使用和无权限基本一致。 (方案二的优势)
    3.方案一较方案二更为纯洁。因为我觉得zk本来就应该是一个底层组件,让他来依赖其它上层的另一个系统?权限的控制精度取决于系统A上信息的准确性。 (方案一的优势)

    另外附上 方案一 有权限和无权限对比压测TPS情况
    测试条件
    :三台ZK服务器:8核 JDK 1.6.0-06 四台zk客户端机器:5核 JDK1.6.0-21
    测试场景:800个发布者,对应800个path,每个path 3个订阅者,共2400个订阅者。发布者发布数据,通知订阅者。
    结论:权限控制对zk的TPS有一定的影响,但是还是保持在较高的水准(1.3w+),如图(点击查看大图):

  • 相关阅读:
    Java面试不得不知的程序(二)
    Java面试不得不知的问题(一)
    Java框架 面试题总结
    JavaSE 面试题总结
    JavaEE 面试题总结
    DBUtils 学习使用
    JavaWeb —— JSP 总结
    java 单例模式(singleton)
    java 上溯造型与下塑造型
    java 第六章 面向对象基础
  • 原文地址:https://www.cnblogs.com/cl1024cl/p/6205145.html
Copyright © 2011-2022 走看看