Если вкратце:
- Создали ACL (статически или динамически)
- Определили роль юзера (как правило используются сессии)
- Проверили наличие привилегии к ресурсу
- Разрешили или отказали (способов отказа как правило несколько, от редиректа до исключения)
Собственно сам ACL (простой и меняется крайне редко, поэтому жёстко захардкожен)
Copy Source | Copy HTML
- /*
* Access control list
*/
- class MyAcl extends Zend_Acl
- {
- public function __construct()
- {
- //roles
- $this->addRole(new Zend_Acl_Role('guest'));
- $this->addRole(new Zend_Acl_Role('user'), 'guest');
- $this->addRole(new Zend_Acl_Role('demo'), 'user');
- $this->addRole(new Zend_Acl_Role('moder'), 'user');
- //resourses
- $this->add(new Zend_Acl_Resource('profile')); //всё что связанно с профилем юзера
- $this->add(new Zend_Acl_Resource('autosearch')); //весь автопоиск юзера
- $this->add(new Zend_Acl_Resource('logs')); //логи скриптов
- $this->add(new Zend_Acl_Resource('others')); //другие фишки для залогиненых
- //юзеры
- $this->allow( 'user', 'profile', array('view', 'edit') );
- $this->allow( 'user', 'autosearch', array('view', 'add', 'del'));
- //$this->allow( 'user', 'monitoring' );
- $this->allow( 'user', 'others', array('searchLimitX2'));
- //модеры
- $this->allow( 'moder', 'logs', array('view'));
- }
- }
Action хелпер для проверки прав
Copy Source | Copy HTML
- /*
* хелпер для проверки прав пользователя
*
* инстанцирует наш ACL
* учитывает незалогиненых юзеров как гостей
*
*/
- class My_Action_Helper_CheckAccess extends Zend_Controller_Action_Helper_Abstract
- {
- private $_hasIdentity;
- private $_role;
- private $_acl;
- public function init()
- {
- $auth = Zend_Auth::getInstance();
- $this->_hasIdentity = $auth->hasIdentity();
- $this->_role = ( $this->_hasIdentity ) ? $auth->getStorage()->read()->role : 'guest';
- $this->_acl = new MyAcl();
- }
- /*
* @param string $mode (redirect | return | excep )
*/
- public function check($resourse, $privileges, $mode)
- {
- $cntr = $this->getActionController();
- $result = $this->_acl->isAllowed( $this->_role, $resourse, $privileges );
- switch ($mode)
- {
- case 'redirect':
- if( !$result )
- {
- $url = $cntr->getHelper('url')->url(array(),'staticLogin',true);
- if( $this->_hasIdentity )
- {
- $message = 'Попробуйте перезайти под другим пользователем.';
- }else{
- $message = 'Войдите в систему';
- $returnUrl = $this->getRequest()->getServer('REQUEST_URI', $cntr->getHelper('url')->url(array(),'userProfile',true) );
- $url .= "?return={$returnUrl}";
- }
- $cntr->getHelper('flashMessenger')->addMessage( array( 'error' => "У вас недостаточно прав для просмотра данной страницы. {$message}.") );
- $cntr->getHelper('redirector')->gotoUrlAndExit( $url );
- }
- break;
- case 'excep':
- if( !$result )
- throw new Exception("Access denied");
- break;
- case 'return':
- return $result;
- break;
- default:
- throw new Exception('Undefined mode (helper access)');
- break;
- }
- }
- public function direct($resourse = null, $privileges = null, $mode = 'return')
- {
- return $this->check($resourse, $privileges, $mode );
- }
- }
Использование (внутри действия)
редирект на форму входа, если нет привелегии view к ресурсу profile
$this->_helper->checkAccess('profile','view','redirect');
исключение, если нет прав на весь ресурс profile
$this->_helper->checkAccess('profile',null,'excep');
возврат результата проверки наличия привилегии add к ресурсу autosearch
$this->_helper->checkAccess('autosearch','add')Несколько пояснений:
- Хук с init() используется не по своему прямому назначению и может быть заменён на __construct()
- Параметр $mode определяет реакцию на отсутствие доступа (редирект на форму входа, исключение или возврат результата)
- В случае редиректа на страницу входа авторизованные пользователи и гости увидят разные сообщения
- Также в случае редиректа отправляется параметр return, для возврата пользователя обратно на запрошенную страницу.
- Метод direct() риализует паттерн стратегия (или я чтото напутал?) и нужен только для удобства использования
ПыСы: если планируется использовать данный хелпер не только через брокер помощников, но и напрямую (например через Zend_Controller_Action_HelperBroker::getStaticHelper('CheckAccess'); ), то необходимо заменить init() на __construct(). Иначе есть риск пропустить этап инита =)
2 комментария:
А почему используете Action Helper?
Не проще ли юзать плагин фронт-контроллера, в котором реализовать метод preDispatch?
Action Helper надо будет вызывать в каждом контроллере, а плагин всего лишь раз прописать и все...
А зачем тут плагин?
Этот хелпер вызывается далеко не в каждом действии, а только когда необходимо проверить привилегии к ресурсу. И вызывать его каждый раз вовсе не надо.
К тому же, если заворачивать это всё в плагин, придётся как либо в этом плагине определять запрошенные привилегию и ресурс. Как вы предлагаете это делать? =)
Отправить комментарий