yii普通filter的accessRules函数中roles属性其实无效

yii提供了完善的角色权限控制,但是那个东西比较庞大,我就希望三级权限即可,游客可以看前台,普通用户和管理员可以登录前台并管理内容,后台只有管理员可登录。并且没有太多的权限需要细分,可以后台可以使用全局的一个权限控制,直接判断是否是管理员即可。

用yii的同学都知道,yiic自动生成的项目中,使用了accessControl这么一个filter,其自动调用Controller的accessRules函数,生成的函数内容数组中,有一个很明显的就是其有roles属性。

我就想,我是否能直接写一个accessRules函数,然后直接只有roles=>admin才是allow操作呢?可是roles又是如何判断的呢?带着问题一路查看源码,在CAccessRule里面有这么一大段。大致是对每条rule会先调用isUserAllowed,这里面又会调用isUserMatched和isRoleMatched,分别对user和role进行检查。

php代码
  1. public function isUserAllowed($user,$controller,$action,$ip,$verb)  
  2. {  
  3.     if($this->isActionMatched($action)  
  4.         && $this->isUserMatched($user)  
  5.         && $this->isRoleMatched($user)  
  6.         && $this->isIpMatched($ip)  
  7.         && $this->isVerbMatched($verb)  
  8.         && $this->isControllerMatched($controller)  
  9.         && $this->isExpressionMatched($user))  
  10.         return $this->allow ? 1 : -1;  
  11.     else 
  12.         return 0;  
  13. }  

 

php代码
  1. protected function isUserMatched($user)  
  2. {  
  3.     if(empty($this->users))  
  4.         return true;  
  5.     foreach($this->users as $u)  
  6.     {  
  7.         if($u==='*')  
  8.             return true;  
  9.         else if($u==='?' && $user->getIsGuest())  
  10.             return true;  
  11.         else if($u==='@' && !$user->getIsGuest())  
  12.             return true;  
  13.         else if(!strcasecmp($u,$user->getName()))  
  14.             return true;  
  15.     }  
  16.     return false;  
  17. }  

是不是很眼熟?对*、?和@进行检查还可以对username进行检查,下面看看对roles是如何检查的,这正式我们想要的重点,我们现在的需求是,后台只需要allow roles=>admin。

php代码
  1. protected function isRoleMatched($user)  
  2. {  
  3.     if(empty($this->roles))  
  4.         return true;  
  5.     foreach($this->roles as $role)  
  6.     {  
  7.         if($user->checkAccess($role))  
  8.             return true;  
  9.     }  
  10.     return false;  
  11. }  

这个函数是用来对roles属性进行逐一验证的,我们发现其通过user的checkAccess函数来对的role进行检查,我们继续看CWebUser,看它具体是如何检查的

php代码
  1. public function checkAccess($operation,$params=array(),$allowCaching=true)  
  2. {  
  3.     if($allowCaching && $params===array() && isset($this->_access[$operation]))  
  4.         return $this->_access[$operation];  
  5.     else 
  6.         return $this->_access[$operation]=Yii::app()->getAuthManager()->checkAccess($operation,$this->getId(),$params);  
  7. }  

只传一个role参数进来的时候,会直接落入第一个if下面的条件,也就是检查CWebUser的_access属性。如此说来,其实我们只要在用户登录后,给他的用户对象设置_access['admin'] = true或者false即可。

下面的问题来了,在CWebUser对象中,并没有提供方法用于操作_access成员数组,而直接操作_access数组也是不可能的,因为它的属性是private。具体可以参见CWebUser的源码,私有变量,无公开函数可供修改,而对accessRules的检查调用直接落入第一个if,因此是无论如何也不可能得到正确的操作的。

搞来搞去,无法直接用简单的access filter,现在要么自己写个filter,要么用yii基于角色的权限控制。我决定后台自己写filter(直接过滤非admin用户),前台用基于角色的权限控制,两不误,都学习,呵呵。

Tags: php, yii
上一篇: 找工作感言
下一篇: zz拼爹时代,看人家的爹在拼什么

相关日志推荐
PHP框架Yaf介绍
AJAX与PHP传递中文数据
YII框架的几个问题
编程中的一些细节问题
zz How to implement COMET with PHP

0 条留言

发表评论

  
  
   (点击图片更换验证码)
点击刷新验证码