yii普通filter的accessRules函数中roles属性其实无效
yii提供了完善的角色权限控制,但是那个东西比较庞大,我就希望三级权限即可,游客可以看前台,普通用户和管理员可以登录前台并管理内容,后台只有管理员可登录。并且没有太多的权限需要细分,可以后台可以使用全局的一个权限控制,直接判断是否是管理员即可。
用yii的同学都知道,yiic自动生成的项目中,使用了accessControl这么一个filter,其自动调用Controller的accessRules函数,生成的函数内容数组中,有一个很明显的就是其有roles属性。
我就想,我是否能直接写一个accessRules函数,然后直接只有roles=>admin才是allow操作呢?可是roles又是如何判断的呢?带着问题一路查看源码,在CAccessRule里面有这么一大段。大致是对每条rule会先调用isUserAllowed,这里面又会调用isUserMatched和isRoleMatched,分别对user和role进行检查。
- public function isUserAllowed($user,$controller,$action,$ip,$verb)
- {
- if($this->isActionMatched($action)
- && $this->isUserMatched($user)
- && $this->isRoleMatched($user)
- && $this->isIpMatched($ip)
- && $this->isVerbMatched($verb)
- && $this->isControllerMatched($controller)
- && $this->isExpressionMatched($user))
- return $this->allow ? 1 : -1;
- else
- return 0;
- }
- protected function isUserMatched($user)
- {
- if(empty($this->users))
- return true;
- foreach($this->users as $u)
- {
- if($u==='*')
- return true;
- else if($u==='?' && $user->getIsGuest())
- return true;
- else if($u==='@' && !$user->getIsGuest())
- return true;
- else if(!strcasecmp($u,$user->getName()))
- return true;
- }
- return false;
- }
是不是很眼熟?对*、?和@进行检查还可以对username进行检查,下面看看对roles是如何检查的,这正式我们想要的重点,我们现在的需求是,后台只需要allow roles=>admin。
- protected function isRoleMatched($user)
- {
- if(empty($this->roles))
- return true;
- foreach($this->roles as $role)
- {
- if($user->checkAccess($role))
- return true;
- }
- return false;
- }
这个函数是用来对roles属性进行逐一验证的,我们发现其通过user的checkAccess函数来对的role进行检查,我们继续看CWebUser,看它具体是如何检查的
- public function checkAccess($operation,$params=array(),$allowCaching=true)
- {
- if($allowCaching && $params===array() && isset($this->_access[$operation]))
- return $this->_access[$operation];
- else
- return $this->_access[$operation]=Yii::app()->getAuthManager()->checkAccess($operation,$this->getId(),$params);
- }
只传一个role参数进来的时候,会直接落入第一个if下面的条件,也就是检查CWebUser的_access属性。如此说来,其实我们只要在用户登录后,给他的用户对象设置_access['admin'] = true或者false即可。
下面的问题来了,在CWebUser对象中,并没有提供方法用于操作_access成员数组,而直接操作_access数组也是不可能的,因为它的属性是private。具体可以参见CWebUser的源码,私有变量,无公开函数可供修改,而对accessRules的检查调用直接落入第一个if,因此是无论如何也不可能得到正确的操作的。
搞来搞去,无法直接用简单的access filter,现在要么自己写个filter,要么用yii基于角色的权限控制。我决定后台自己写filter(直接过滤非admin用户),前台用基于角色的权限控制,两不误,都学习,呵呵。
0 条留言
发表评论