在我正在进行的一个项目中,我遇到了各种用户遇到浏览器超时的问题。这意味着 Zend_Auth 不再存在于注册表中,用户无法访问所需的页面/功能。
为了阻止这种情况发生,我设置了一个插件(如您所建议的那样)并让该插件在 preDispatch() 中执行检查。下面是一个例子:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
public function run()
{
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new App_Controller_Plugin_Timeout());
parent::run();
}
}
超时类实现任何 Zend_Auth 或 Zend_Acl 要求,通过下面的函数使用检查。
class App_Controller_Plugin_Timeout extends Zend_Controller_Plugin_Abstract
{
/**
* Validate that the user session has not timed out.
* @param Zend_Controller_Request_Abstract $request
* @return void
* @todo Validate the user has access to the requested page using Zend_Acl
*/
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$frontController = Zend_Controller_Front::getInstance();
$controllerName = $frontController->getRequest()->getControllerName();
$actionName = $frontController->getRequest()->getActionName();
$authInstance = Zend_Auth::getInstance();
/** If the controller is not the Auth or Error controller, then check for
* a valid authorized user and redirect to the login page if none found */
if (($controllerName !== 'auth') && ($controllerName !== 'index') && ($controllerName !== 'error')) {
if (!$authInstance->hasIdentity()) {
$this->_response->setRedirect('/index/timeout')->sendResponse();
exit;
}
} else if (($controllerName == 'index') || (($controllerName == 'auth') && ($actionName !== 'logout'))) {
/** If running the Auth or Index (default) controller (and not the logout
* action), check if user already signed in and redirect to the welcome page */
if ($authInstance->hasIdentity()) {
$this->_response->setRedirect('/general/welcome')->sendResponse();
exit;
}
}
}
}
....
/**
* Test that the input user belongs to a role based on the user input and
* the values loaded into the Acl registry object setup when the site first
* loads
*
* @param mixed|Zend_Auth $userData
* @param string $userRole
* @return boolean
* @throws Zend_Exception When invalid input is provided
*/
public function isUserMemberOfRole($userData, $userRole)
{
if (empty($userData)) {
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity()) {
$userData = $auth->getIdentity();
} else {
return FALSE;
}
}
if (!is_string($userRole)){
throw new Zend_Exception('Invalid input provided to ' . __METHOD__);
}
// Setup the required variables and access the registry for the Acl values
$rolesTable = new App_Model_Internal_UsersToRoles();
$registry = Zend_Registry::getInstance();
$acl = $registry->get('acl');
$roles = $rolesTable->getUserRoles($userData); // returns an array of values
foreach ($roles as $value) {
if ($value['Name'] == $userRole) {
return $acl->isAllowed($value['Name'], null, $userRole);
}
}
}
我在数据库表中实现了用户访问,然后在 Bootstrap->run() 中初始化为“_init”函数,如下所示:
protected function _initAclObjectForUserRoles()
{
$userTable = new App_Model_Internal_Roles();
$acl = new Zend_Acl();
$userRoles = $userTable->fetchAll();
$roles = $userRoles->toArray();
// Cycle through each Role and set the allow status for each
foreach($roles as $value) {
$department = $value['Name'];
$acl->addRole(new Zend_Acl_Role($department));
$acl->allow($department, null, $department);
}
// Add the new Acl to the registry
$registry = Zend_Registry::getInstance();
$registry->set('acl', $acl);
}
因此,使用这种方法,您可以通过从数据库加载的角色将访问限制设置到 Zend_Acl 对象中,或者您可以通过 Timeout 插件加载控制器类属性并检查它的值。虽然,我发现在数据库中维护访问策略比在整个代码库中传播它们更容易...... :-)