Redirecionar regras de access com Yii

Estou fazendo um aplicativo que requer autenticação. Na página de índice do aplicativo, eu especifiquei as regras de access como esta

public function accessRules() { return array( array('deny', 'actions'=>array('index','register','login','password'), 'users'=>array('@'), ), array('allow', 'users'=>array('*') ), ); } 

Na primeira regra, as ações ‘índice’, ‘registrar’, ‘login’ e ‘senha’ são tornadas inacessíveis para usuários autenticados. No entanto, não quero mostrar esta mensagem

 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. 

… para os usuários autenticados quando tentam acessar essas ações. Em vez disso, eu quero redirecioná-los para outra página. Seria útil se eu pudesse fazer algo assim na primeira regra

 array('redirect', 'actions'=>array('index','register','login','password'), 'users'=>array('@'), 'url'=>array('home/index'), ), 

Eles vão fazer você uma oferta que você não pode recusar

Começando com Yii v1.1.11 CAccessRule define a propriedade deniedCallback que facilmente permite que você defina um redirecionamento quando o access é negado. Eu não quero roubar o trovão de Iain Gray , então vá até cima sua resposta (graças ao comentarista que me alertou para isso também).

A resposta original segue.

Opção 1: estenda Yii para habilitar esta funcionalidade (correta)

Para fazer isso, precisamos escrever nossas próprias aulas para serem usadas em vez de CAccessRule e CAccessControlFilter . Para CAccessRule , precisamos apenas adicionar uma propriedade adicional:

 class MyAccessRule extends CAccessRule { public $redirect; // just add this property } 

Para CAccessControlFilter , queremos que ele reconheça o valor desta propriedade e atue sobre ela. Para fazer isso, precisamos replace o método preFilter . A partir da implementação do estoque , faça algumas mudanças:

 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; } } 

Então, também precisamos replace o método setRules , para instruir o filtro a usar a class MyAccessRule vez do CAccessRule padrão. Mais uma vez, modificamos a implementação de estoque mudando a linha

 $r=new CAccessRule; 

ler

 $r=new MyAccessRule; 

Depois de criar essas classs, também devemos injetá-las no pipeline de Yii. Para fazer isso, substitua filterAccessControl na class do controlador base; novamente, tomando a implementação de estoque como referência e fazendo uma pequena mudança:

 public function filterAccessControl($filterChain) { $filter=new MyAccessControlFilter; // CHANGED THIS $filter->setRules($this->accessRules()); $filter->filter($filterChain); } 

É isso aí! Agora você pode aproveitar a funcionalidade adicional em qualquer controlador fornecendo o novo parâmetro de redirect para os filtros de controle de access como este:

 public function accessRules() { return array( array('deny', 'actions'=>array('index','register','login','password'), 'users'=>array('@'), 'redirect'=>array('home/index'), ), ); } 

Opção 2: implementar controle de access dentro de cada ação (a ser evitada)

Se você não estiver confortável com a subclass dos componentes principais do Yii, outra opção que eu não recomendo é incorporar o controle de access e a lógica de redirecionamento dentro de cada ação do controlador que você deseja proteger ou replace o método beforeAction em seus controladores para cobrir várias ações de um local.

Desde Yii v1.1.11 você pode fazer o mesmo com um retorno de chamada e um encerramento, e apenas as classs padrão:

 array('deny', 'actions'=>array('index','register','login','password'), 'users'=>array('@'), 'deniedCallback' => function() { Yii::app()->controller->redirect(array ('/home/index')); } ), 

Este funcionou para mim desde que eu 1.1.11:

  array('deny', // deny all users 'users'=>array('*'), 'deniedCallback' => $this->redirect('/') ), 

ou use um método estático em uma class:

 'deniedCallback' => array('ClassName', 'staticMethodName'), 

$request->redirect($app->createUrl($rule->redirect));

Deveria estar:

 if(is_array($rule->redirect) && isset ($rule->redirect[0])){ $request->redirect($app->createUrl($rule->redirect[0])); }