我目前有一个登录页面,它可以提供给中央身份验证服务.我想对用户进行权限检查.如果用户未登录,我想将它们重定向到登录页面,并让登录页面重定向它们以执行它们最初执行的任何操作,再次运行访问检查.如果他们没有权限,我想将他们重定向到访问被拒绝的页面.
这是我到目前为止所做的:
将此行添加到我的application.ini:
resources.frontController.actionHelperPaths.Cas_Controller_Action_Helper = APPLICATION_PATH "/controllers/helpers"
创建了文件$/ application / controllers / helpers / PermissionRequire.PHP:
<?PHP /** * This class is used in order to require that a user have a given privilege before continuing. * * @copyright 2011 Case Western Reserve University,College of Arts and Sciences * @author Billy O'Neal III (bro4@case.edu) */ class Cas_Controller_Action_Helper_PermissionRequire extends Zend_Controller_Action_Helper_Abstract { /** * Cleans up the supplied list of privileges. Strings are turned into the real privilege objects (Based on name),* privilege objects are left alone. * * @static * @param array|Privilege|string $privileges * @return array */ private static function CleanPrivileges($privileges) { if (!is_array($privileges)) { $privileges = array ( $privileges ); } $strings = array_filter($privileges,'is_string'); $objects = array_filter($privileges,function($o) { return $o instanceof Privilege; }); $databaSEObjects = PrivilegeQuery::create()->filterByName($strings)->find(); return array_combine($objects,$databaSEObjects); } /** * Generic implementation for checking whether a user can visit a page. * @param Privilege|string|array $privileges Any number of privileges which are required to access the given * page. If ANY privilege is held by the user,access is allowed. * @param AccessControlList The acl which is being checked. Defaults to the application. */ public function direct($privileges,$acl = null) { $privileges = self::CleanPrivileges($privileges); if ($acl === null) { $acl = AccessControlListQuery::getApplication(); } $redirector = $this->getActionController()->getHelper('redirector'); /** @var Zend_Controller_Action_Helper_Redirector $redirector */ $redirector->setCode(307); if (Cas_Model_CurrentUser::IsLoggedIn() && (!Cas_Model_CurrentUser::AccessCheck($acl,$privileges))) { $redirector->gotoSimple('accessdenied','login'); } else { $returnData = new Zend_Session_Namespace('Login'); $returnData->params = $this->getRequest()->getParams(); $redirector->setGotoSimple('login','login'); $redirector->redirectAndExit(); } } }
这是LoginController:
<?PHP /** * LoginController - Controls login access for users */ require_once 'CAS.PHP'; class LoginController extends Zend_Controller_Action { /** * Logs in to the system,and redirects to the calling action. * * @return void */ public function loginAction() { //Authenticate with Login.Case.Edu. PHPCAS::client(CAS_VERSION_2_0,'login.case.edu',443,'/cas',false); PHPCAS::setNoCasServerValidation(); PHPCAS::forceAuthentication(); $user = CaseIdUser::createFromLdap(PHPCAS::getUser()); Cas_Model_CurrentUser::SetCurrentUser($user->getSecurityIdentifier()); $returnData = new Zend_Session_Namespace('Login'); /** @var array $params */ $redirector = $this->_helper->redirector; /** @var Zend_Controller_Action_Helper_Redirector $redirector */ $redirector->setGotoRoute($returnData->params,'default',true); $returnData->unsetAll(); $redirector->redirectAndExit(); } /** * Logs the user out of the system,and redirects them to the index page. * * @return void */ public function logoutAction() { Cas_Model_CurrentUser::logout(); $this->_helper->redirector->gotoRoute('index','index',true); } /** * Returns an access denied view. * * @return void */ public function accessdeniedAction() { //Just display the view and punt. } }
问题是,在登录控制器准备URL以重定向用户时,似乎“params”为空.此外,当控制器的POST数据调用$this-> _helper-> permissionRequire(SOME PRIVILEGE)时,这将不起作用.
有没有更好的方法来存储请求的整个状态,并咳嗽与该请求完全匹配的重定向?
附:哦,这是一个使用该帮助器的示例控制器:
<?PHP /** * Serves as the index page; does nothing but display views. */ class IndexController extends Zend_Controller_Action { public function indexAction() { $renderer = $this->getHelper('VieWrenderer'); /** @var $renderer Zend_Controller_Action_Helper_VieWrenderer */ if (Cas_Model_CurrentUser::IsLoggedIn()) { $this->_helper->permissionRequire(Cas_Model_Privilege::GetLogin()); $this->render('loggedin'); } else { $this->render('loggedout'); } } }
解决方法
在你的配置中:
resources.frontController.plugins[] = "Cas_Controller_Plugin_Authenticator"
这是插件:
class Cas_Controller_Plugin_Authenticator extends Zend_Controller_Plugin_Abstract { public function routeStartup( Zend_Controller_Request_Abstract $request ) { if( Zend_Auth::getInstance()->hasIdentity() ) { if( null !== $request->getParam( 'from-login',null ) && Zend_Session::namespaceIsset( 'referrer' ) ) { $referrer = new Zend_Session_Namespace( 'referrer' ); if( isset( $referrer->request ) && $referrer->request instanceof Zend_Controller_Request_Abstract ) { Zend_Controller_Front::getInstance()->setRequest( $referrer->request ); } Zend_Session::namespaceUnset( 'referrer' ); } } else { $referrer = new Zend_Session_Namespace( 'referrer' ); $referrer->request = $this->getRequest(); return $this->_redirector->gotoRoute( array( 'module' => 'default','controller' => 'user','action' => 'login' ),true ); } } }
>如果用户不是:它将当前请求对象保存在会话中并重定向到UserController :: loginAction(). (见下文)
>如果用户IS:它从会话中检索保存的请求对象(如果可用,如果用户刚刚登录则为AND)并替换frontController中的当前请求对象(我应该考虑代理路由器).
总而言之,如果您想要更灵活地确定哪些模块/控制器/操作参数需要身份验证和授权(我想你想要),您可能希望将一些检查移动到另一个钩子而不是routeStartup:即routeShutdown,dispatchLoopStartup或predispatch.因为到那时应该知道行动参数.作为额外的安全措施,您可能还需要比较原始请求的操作参数(模块/控制器/操作)和替换请求,以确定您是否处理了正确保存的请求.
此外,您可能需要在新请求对象的某些或所有挂钩中设置$request-> setdispatched(false).但不完全确定:见docs.
class UserController extends Zend_Controller_Action { public function loginAction() { $request = $this->getRequest(); if( $request->isPost() ) { if( someAuthenticationProcessIsValid() ) { if( Zend_Session::namespaceIsset( 'referrer' ) ) { $referrer = new Zend_Session_Namespace( 'referrer' ); if( isset( $referrer->request ) && $referrer->request instanceof Zend_Controller_Request_Abstract ) { return $this->_redirector->gotoRoute( array( 'module' => $referrer->request->getModuleName(),'controller' => $referrer->request->getControllerName(),'action' => $referrer->request->getActionName(),'from-login' => '1' ),true ); } } // no referrer found,redirect to default page return $this->_redirector->gotoRoute( array( 'module' => 'default','controller' => 'index','action' => 'index' ),true ); } } // GET request or authentication Failed,show login form again } }
出于安全原因,您可能希望设置一个到期跳数为1的会话变量,而不是“from-login”查询字符串变量.
最后,说了这么多;你可能想彻底考虑一下你是否真的想要这种行为.正如您所知,POST请求通常会禁止敏感状态更改操作(创建,删除等).我不确定用户在登录后是否正常期望这种行为(在他们的会话刚刚过期之后).此外,您可能想要考虑可能导致应用程序本身出现意外行为的可能情况.我现在想不出任何具体细节,但如果我更多地考虑它,我相信我能想出一些.
HTH