Zend_Acl的误解
很多人会误认为ACL的resource和privilege是controller和action,这是错误的。
对Zend_Acl而言,resource可以是任何事物-一个controller,一个file,一个module...
privilege就像resource一样,也可以是任何与resource相关的事物,例如,如果resource是一个controler,那privilege就可以是一个action,或者如果controller是一个file或者model,那么它就可能是read或者write。
创建一个简单的ACL
前面提到,Zend_Acl是由资源(resources)、权限(privileges)和角色(roles)构成的。privileges是访问resources的权限级别。roles就是以指定的访问权限(privilege)来访问resource的访问对象,可以是一个用户,用户组or anything you wish to associate such data with。
下面是一个ACL的简单代码,只包含了少量的resources和roles
1 class My_Acl extends Zend_Acl { 2 public function __construct() { 3 //Add a new role called "guest" 4 $this->addRole(new Zend_Acl_Role('guest')); 5 6 //Add a role called user, which inherits from guest 7 $this->addRole(new Zend_Acl_Role('user'), 'guest'); 8 9 //Add a resource called page 10 $this->add(new Zend_Acl_Resource('page')); 11 12 //Add a resource called news, which inherits page 13 $this->add(new Zend_Acl_Resource('news'), 'page'); 14 15 //Finally, we want to allow guests to view pages 16 $this->allow('guest', 'page', 'view'); 17 18 //and users can comment news 19 $this->allow('user', 'news', 'comment'); 20 } 21 }
此时创建一个My_Acl的实例,就可以对应一些简单的权限对应设定,但是具体那个角色拥有什么权限呢?
guest角色对于page资源拥有一个view的权限,之后user角色继承了guest,所以user也拥有了page的view权限。news资源继承了page,所以所有用户对news资源都拥有与对page资源相同的权限。在构造函数的最后一行,我们为user角色在news资源上新增了一个comment的权限。而此时只有user角色拥有news资源的comment权限,guest没有。
使用ACL
使用一个ACL类非常简单。你只需要调用isAllowed方法,同时向它传递一个role,resource和一个privilege参数既可。而最大的难点在于你如何确定哪个是role, resource和privilege。
该如何确定哪个是角色?一个非常简单的假设就是:如果这有一个登陆用户user,那么这个角色就是user,否则就是guest。
那么资源呢?这取决于你的应用程序,这可以从你所包含的文件名中猜测出来。例如:对于上面的例子中,我们有一个page.php文件和一个news.php文件用来对应于page资源,而news对应于news资源。
最后什么是权限呢?当我们简单的读取page的时候,你可以使用view权限。稍后代码会检测一些其它一些权限规则,例如comment权限以及显示comment box的权限等。
下面是一个简单的实例
1 $role = 'guest'; 2 if(isset($_SESSION['auth'])) 3 $role = 'user'; 4 5 $acl = new My_Acl(); 6 7 if($acl->isAllowed($role, 'news', 'comment')) { 8 //Some code here to display a news box 9 }
在ZF项目中使用ACL
在zf项目中,资源和权限通常会在请求资源中确定。
通常我们可以创建一个检测权限的插件:
1 class My_Plugin_Acl extends Zend_Controller_Plugin_Abstract { 2 private $_acl = null; 3 4 public function __construct(Zend_Acl $acl) { 5 $this->_acl = $acl; 6 } 7 8 public function preDispatch(Zend_Controller_Request_Abstract $request) { 9 //As in the earlier example, authed users will have the role user 10 $role = (Zend_Auth::getInstance()->hasIdentity()) 11 ? 'user' 12 : 'guest'; 13 14 //For this example, we will use the controller as the resource: 15 $resource = $request->getControllerName(); 16 17 if(!$this->_acl->isAllowed($role, $resource, 'view')) { 18 //If the user has no access we send him elsewhere by changing the request 19 $request->setModuleName('auth') 20 ->setControllerName('auth') 21 ->setActionName('login'); 22 } 23 } 24 }
我们可以在上面的例子中创建一个静态方法来代替构造函数。
将上面的插件加载到前段控制器中:
1 $acl = new My_Acl(); 2 3 //assuming $fc is the front controller 4 $fc->registerPlugin(new My_Plugin_Acl($acl));
此时每个请求都会核对权限控制列表,并且没有view权限的角色将会别拒绝访问。
接下来就是关于如何检测comment权限
在需要检测comment权限的controller中添加一些代码来向view中传递一个boolean值来确定权限。
1 public function someAction() { 2 $role = (Zend_Auth::getInstance()->hasIdentity()) 3 ? 'user' 4 : 'guest'; 5 6 //assuming $this->_acl contains the acl 7 $this->view->canComment = $this->_acl->isAllowed($role, 'news', 'comment'); 8 }
创建自定义角色类
通过扩展Zend_Acl_Role_Interface接口来定义角色类,使其具有更多的灵活性。该接口只包含一个方法getRoleId()
1 class Common_Module_acl_user implements Zend_Acl_Role_Interface 2 { 3 protected $_name; 4 5 public function __construct($name) 6 { 7 $this->_name = $name; 8 } 9 10 public function getRoleId() 11 { 12 return 'user_'. $this->_name; 13 } 14 }
此时只需将该类的实例传递给Zend_Acl对象既可
1 $acl = new Zend_Acl(); 2 //添加一个名为user_zh的角色 3 $acl->addRole(new Common_Module_acl_user('zh'));
创建自定义资源类
通过扩展Zend_Acl_Resource_Interface接口来实现自定义资源类
1 class Resource_Controller implements Zend_Acl_Resource_Interface { 2 public function __construct($id) { 3 $this->_id = $id; 4 } 5 6 public function getResourceId() { 7 return 'controller-' . $this->_id; 8 } 9 }
实现方法同角色类一样
PHP技术交流群 170855791