Я делаю приложение, требующее аутентификации. На странице индекса приложения я указал правила доступа, подобные этому
public function accessRules() { return array( array('deny', 'actions'=>array('index','register','login','password'), 'users'=>array('@'), ), array('allow', 'users'=>array('*') ), ); }
При первом правиле индексы действий, регистра, входа и пароля становятся недоступными для аутентифицированных пользователей. Однако я не хочу показывать это сообщение
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.1.11 CAccessRule
определяет свойство deniedCallback
которое легко позволяет вам определять перенаправление при отказе доступа. Я не хочу воровать гром Иэна Грея , поэтому поднимите его ответ (спасибо комментатору, который также предупредил меня об этом).
Исходный ответ следует.
Для этого нам нужно будет написать собственные классы, которые будут использоваться вместо 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'), ), ); }
Если вам неудобно подклассифицировать основные компоненты Yii, другой вариант, который я не рекомендую, заключается в том, чтобы встраивать логику управления доступом и перенаправления в каждое действие контроллера, которое вы хотите защитить, или переопределять метод beforeAction
на ваших контроллерах для покрытия нескольких действий с одно место.
Поскольку Yii v1.1.11 вы можете сделать то же самое с обратным вызовом и закрытием, а также только классы по умолчанию:
array('deny', 'actions'=>array('index','register','login','password'), 'users'=>array('@'), 'deniedCallback' => function() { Yii::app()->controller->redirect(array ('/home/index')); } ),
этот работал для меня с 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])); }