我正在做一个需要身份验证的应用程序。在应用程序的索引页面中,我指定了类似的访问规则
public function accessRules() {
return array(
array('deny',
'actions'=>array('index','register','login','password'),
'users'=>array('@'),
),
array('allow',
'users'=>array('*')
),
);
}
在第一条规则中,操作"index"、"register"、"login"answers"password"对经过身份验证的用户是不可访问的。但是,我不想显示此消息
Unauthorized
You are not authorized to perform this action.
You do not have the proper credential to access this page.
If you think this is a server error, please contact the webmaster.
当经过身份验证的用户尝试访问这些操作时,向他们发送。相反,我想将它们重定向到另一个页面。如果我能在的第一条规则中做这样的事情,那将是有用的
array('redirect',
'actions'=>array('index','register','login','password'),
'users'=>array('@'),
'url'=>array('home/index'),
),
自从Yii v1.11.1以来,您可以通过回调和闭包做同样的事情,只需要默认的类:
array('deny',
'actions'=>array('index','register','login','password'),
'users'=>array('@'),
'deniedCallback' => function() { Yii::app()->controller->redirect(array ('/home/index')); }
),
他们会给你一个无法拒绝的报价
从Yii v1.11.1开始,CAccessRule
定义了deniedCallback
属性,该属性允许您在拒绝访问时轻松定义重定向。我不想抢伊恩·格雷的风头,所以投票支持他的回答(感谢提醒我这一点的评论者)。
原来的答案如下。
选项1:扩展Yii以启用此功能(正确)
要做到这一点,我们需要编写自己的类来代替CAccessRule
和CAccessControlFilter
。对于CAccessRule
,我们只需要添加一个额外的属性:
class MyAccessRule extends CAccessRule {
public $redirect; // just add this property
}
对于CAccessControlFilter
,我们想让它识别这个属性的值并对它采取行动。要做到这一点,我们需要重写preFilter
方法。从库存实施开始,进行一些更改:
class MyAccessControlFilter extends CAccessControlFilter {
protected function preFilter($filterChain)
{
$app=Yii::app();
$request=$app->getRequest();
$user=$app->getUser();
$verb=$request->getRequestType();
$ip=$request->getUserHostAddress();
foreach($this->getRules() as $rule)
{
if(($allow=$rule->isUserAllowed($user,
$filterChain->controller,
$filterChain->action,
$ip,
$verb))>0) // allowed
break;
else if($allow<0) // denied
{
// CODE CHANGED HERE
$request->redirect($app->createUrl($rule->redirect));
return false;
}
}
return true;
}
}
然后,我们还需要重写setRules
方法,以指示过滤器使用MyAccessRule
类而不是标准的CAccessRule
。再次,我们通过更改行来修改库存实现
$r=new CAccessRule;
读取
$r=new MyAccessRule;
在创建这些类之后,我们还必须将它们注入Yii的管道中。要执行此操作,请覆盖基本控制器类上的filterAccessControl
;再次,以库存实现为参考,并进行一个小的更改:
public function filterAccessControl($filterChain)
{
$filter=new MyAccessControlFilter; // CHANGED THIS
$filter->setRules($this->accessRules());
$filter->filter($filterChain);
}
就是这样!现在,您可以通过向访问控制过滤器提供新的redirect
参数来利用任何控制器中的额外功能,如下所示:
public function accessRules() {
return array(
array('deny',
'actions'=>array('index','register','login','password'),
'users'=>array('@'),
'redirect'=>array('home/index'),
),
);
}
选项2:在每个动作中实施访问控制(要避免)
如果您对Yii的核心组件的子类化感到不舒服,我不建议的另一个选项是在您想要保护的每个控制器操作中嵌入访问控制和重定向逻辑,或者覆盖控制器上的beforeAction
方法,以覆盖一个位置的多个操作。
这一个自yii 1.1.11:以来一直为我工作
array('deny', // deny all users
'users'=>array('*'),
'deniedCallback' => $this->redirect('/')
),
或者在类中使用静态方法:
'deniedCallback' => array('ClassName', 'staticMethodName'),
$request->redirect($app->createUrl($rule->redirect));
应为:
if(is_array($rule->redirect) && isset ($rule->redirect[0])){
$request->redirect($app->createUrl($rule->redirect[0]));
}