ThinkPHP框架使用Zend ACL权限包

由于种种机缘巧合用Zend Framework框架做过一年的项目,所以,对ZF框架的相关的包也有着一定的了解,前些天用TP的RBAC发现要用数据库,而且使用起来也不是很顺手,也许是自己有着偏见的缘故吧,于是就放弃了TP提供的RBAC权限,选用了ZEND ACL.

第一步:从Zend官方下载ZF框架包,解压后将里面的Acl包与Acl包同级目录下的Acl.php文件也一起拷贝至TP框架提供的第三方类库目录Vendor/Zend.

第二步:由于在使用ZEND ACL的时候,我使用了ini格式的配置文件,同时也方便ACL读取ini文件,这个地方用到了Zend Config这个包,也将这个包拷贝到Vendor/Zend目录,还有与Config同目录下的Config.php文件也拷贝到Vendor/Zend目录.

第三步:由于这两个包都用到了Zend_Exception这个类,所以,要将Zend目录下的Exception.php文件拷贝到Vendor目录下。

注:为什么要有Zend目录,因为,Acl和Config包都在相互引用类的时候都用到了Zend这个目录,所以,保证程序正常引用,必须将Acl和Config包放在Vendor/Zend目录下.

第四步:配置资源,所谓资源就是我们要进行用ACL管理的资源,只有这些资源才会被ACL进行管理,没有在配置之列的资源将不会适用ACL控制,因为我的程序是使用的分组。所以,在Conf目录下有一个分组目录Admin. Admin目录下我创建了一个acl.ini文件,这个文件用来保存我们要进行控制的资源.

格式如:

;;==========================================

;;访问控制列表(ACL)设置说明:

;;1、resources为资源列表,仅对资源列表中的资源进行控制

;;2、resources格式:自定义名称.键名(任意,但不可用重复)= 模块:控制器

;;3、这里将Zend ACL移动到Thinkphp中来使用,这里配置与Zend里面的配置无二。

;; admin指的要将此运用到哪个分组[这里Admin分组],如果没有分组是独立的,那么随机设置一个。在ACL类里面自己匹配。

;; 这里必须将'admin:'后面的小写,不管你的操作是大写还是小写,这里都必须小写。

;;==========================================

  1. [ACL]
  2. ;;====resource资源部分
  3. resource.index = Admin:index
  4. resource.ad = Admin:ad
  5. resource.article = Admin:article
  6. resource.grievance = Admin:grievance
  7. resource.login = Admin:login
  8. resource.secret = Admin:secret
  9. resource.user = Admin:user
  10. resource.common = Admin:common

第五步:创建控制类,有了资源,我们还要指定角色与分配资源,因为,一般后台程序或其他管理程序同时会有多个角色进行操作,而每个角色所能操作的权限不同,不同的权限对应的资源也不一样,所以,我们要通过这个类来细化规则,如下:

  1. class AdminAcl
  2. {
  3. // 默认角色
  4. private $_defaultRole = 'guest';
  5. public function __construct()
  6. {
  7. Vendor('Zend.Acl');
  8. Vendor('Zend.Config.ini');
  9. $this->acl = new Zend_Acl();
  10. // 定义了三个角色:默认[游客]角色、客服角色、超级管理员角色。
  11. $this->acl->addRole(new Zend_Acl_Role($this->_defaultRole));
  12. $this->acl->addRole(new Zend_Acl_Role('service'));
  13. $this->acl->addRole(new Zend_Acl_Role('admin'));
  14. // 读取配置文件。配置文件指明了需要进行控制的类型。
  15. $aclConfig = new Zend_Config_Ini(APP_PATH . '/Conf/Admin/acl.ini', 'ACL');
  16. $aclSettings = $aclConfig->toArray();
  17. // 添加资源
  18. foreach ($aclSettings as $key => $arr) {
  19. $this->acl->add(new Zend_Acl_Resource($key));
  20. foreach ($arr as $value){
  21. $this->acl->add(new Zend_Acl_Resource($value), $key);
  22. }
  23. }
  24. // 游客权限,可以访问的资源:这里只能访问登录模块的index
  25. // 第三个参数是用户可以访问的操作。
  26. $this->acl->allow('guest', 'Admin:login', array('index'));
  27. // 客服权限。
  28. $this->acl->allow('service', 'Admin:login');
  29. $this->acl->allow('service', 'Admin:index');
  30. $this->acl->allow('service', 'Admin:ad');
  31. $this->acl->allow('service', 'Admin:article');
  32. $this->acl->allow('service', 'Admin:grievance');
  33. $this->acl->allow('service', 'Admin:secret');
  34. //$this->acl->allow('service', 'admin:user'); // 用户管理必须超级管理员。
  35. //$this->acl->allow('service', 'admin:common');
  36. // 超级管理员可以访问任意资源
  37. $this->acl->allow('admin');
  38. $this->preDispatch();
  39. }
  40. public function preDispatch()
  41. {
  42. $role = $this->_defaultRole; // 默认角色为游客。
  43. // 首先第一步取用户信息,相关的验证放到这里即可。
  44. $is_login = true;
  45. if ($is_login)
  46. {
  47. $userinfo = array('usertype' => 3);
  48. if ($userinfo['usertype'] == 1)
  49. {
  50. $role = 'admin';
  51. }
  52. elseif ($userinfo['usertype'] == 2)
  53. {
  54. $role = 'service';
  55. }
  56. }
  57. // 判断角色是否在注册的角色里面。
  58. if (!$this->acl->hasRole($role))
  59. {
  60. $role = 'guest';
  61. }
  62. $group_name = GROUP_NAME;
  63. $module_name = strtolower(MODULE_NAME);
  64. $action_name = strtolower(ACTION_NAME);
  65. $resource = "$group_name:$module_name";
  66. if (!$this->acl->has($resource))
  67. {
  68. $resource = null;
  69. }
  70. // 若是没有权限则将跳转到登录页面。
  71. if (!$this->acl->isAllowed($role, $resource, $action_name))
  72. {
  73. redirect(U('Admin-Login/index'));
  74. }
  75. }
  76. }

注:APP_PATH 这个是一个常量,这个常量我在项目入口文件index.php文件中定义了,它的值是入口文件所在目录,这样的话,就相当于当前项目的目录路径,因为我刚才将acl.ini放在了Conf/Admin目录下了.

以上这个类我们放在了项目目录下的Commmon/Admin分组目录下,取名为AdminAcl.class.php.

第六步:在调用任何操作之前调用此控制类,这一步就很简单了,因为,我们在做项目的时候都会把会创建一个CommonAction.class.php文件或类让其他所有的Action继承,所以,这个我在CommonAction类里的_initialize()方法里面进行调用控制类.调用方法如:

  1. public function _initialize()
  2. {
  3. import('AdminAcl', 'Common/Admin');
  4. new AdminAcl();
  5. }

这样每次执行其他Action的时候都会调用执行这个初始化方法,就会自动调用AdminAcl这个资源控制类,就会按照这个类中的preDespatch()方法的规则进行判断控制.

结后语:其实在第五步的时候,最后我们调用了redirect()方法进行跳转,这个方法是TP系统函数,里面的URL地址可以配置在分组配置中,这样达到一个全自动或半自动的效果.

以上用法在ZF里面是非常常见的,如果TP使用不到,那在ZF框架里面一定会用到.