代码之家  ›  专栏  ›  技术社区  ›  PvB

如何在Zend框架中进行预补丁转发?

  •  3
  • PvB  · 技术社区  · 14 年前

    我想用 _forward() 在里面 preDispatch 在检查用户是否登录到每个控制器之后。

    这个场景非常简单:如果用户没有登录,那么应该将其转发到 loginAction 在同一个控制器或另一个控制器中。

    这将导致无限循环,因为调度过程再次开始,调用 预调度 再次,转发将再次启动所有操作。

    我唯一能想到的解决办法是检查 登录行为 已在请求中设置。

    所以我的问题是,成熟的开发人员如何处理这个问题?

    更新 就在按下“发送”按钮后,神圣意识的幽灵出现了;) 另一个想法是建立一个 LoginController 处理登录请求。或者有更好的方法吗?

    3 回复  |  直到 12 年前
        1
  •  9
  •   hobodave    14 年前

    我使用Zend_控制器插件和AuthController的组合来保护我的站点。它支持密码重置、强制密码更改和自动帐户锁定,因此具有中等的复杂性。

    请注意,我使用的是条令,所以显然这不能只是剪切和粘贴到您的应用程序中,但它应该以最小的更改发挥作用。我删除了一些特定于我的应用程序的方法,但是所有的通用认证foo都存在。

    插件

    <?php
    class Hobo_Controller_Plugin_Auth extends Zend_Controller_Plugin_Abstract
    {
        public function preDispatch(Zend_Controller_Request_Abstract $request)
        {
            $auth = Zend_Auth::getInstance();
            if ($auth->hasIdentity()) {
                if ('logout' != $request->getActionName()) {
                    if (! $request->getParam('force_password_change')
                        && $this->_checkPasswordExpiry($auth->getIdentity()->username)
                    ) {
                        $request->setParam('force_password_change', true);
                        $request->setModuleName('default')
                            ->setControllerName('auth')
                            ->setActionName('change-password');
                    }
                }
            } else {
                // Defer more complex authentication logic to AuthController
                if ('auth' != $this->getRequest()->getControllerName()) {
                    $redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
                    $redirector->gotoSimple('restricted', 'auth');
                }
            }
        }
    
        protected function _checkPasswordExpiry($username)
        {
            // Look up user and return true if password is expired
        }
    }
    

    自动控制器

    <?php
    
    class AuthController extends Zend_Controller_Action
    {
        public function init()
        {
            $this->_auth = Zend_Auth::getInstance();
    
            $this->_errorMessenger = new Zend_Controller_Action_Helper_FlashMessenger();
            $this->_errorMessenger->setActionController($this)->init();
            $this->_errorMessenger->setNamespace('error');
    
            $this->_noticeMessenger = new Zend_Controller_Action_Helper_FlashMessenger();
            $this->_noticeMessenger->setActionController($this)->init();
            $this->_noticeMessenger->setNamespace('notice');
    
            $this->view->errors = $this->_errorMessenger->getMessages();
            $this->view->notices = $this->_noticeMessenger->getMessages();
        }
    
        public function preDispatch()
        {
            if (! $this->_auth->hasIdentity()) {
                if (! in_array($this->_request->getActionName(), array(
                        'logout', 'identify', 'forgot-password', 'reset-password', 'restricted'))
                    ) {
                    $this->_redirect('/auth/restricted');
                }
            }
        }
    
        public function restrictedAction()
        {
            // Shows access restricted page
        }
    
        public function logoutAction()
        {
            $this->_auth->clearIdentity();
            Zend_Session::destroy();
            $this->_redirect('/');
        }
    
        public function identifyAction()
        {
            if ($this->_request->isPost()) {
                $username = $this->_getParam('username');
                $password = $this->_getParam('password');
    
                if (empty($username) || empty($password)) {
                    $this->_flashError('Username or password cannot be blank.');
                } else {
                    $user = new dUser();
                    $result = $user->login($username, $password);
    
                    if ($result->isValid()) {
                        $user->fromArray((array) $this->_auth->getIdentity());
    
                        if ($this->_getParam('changepass') || $user->is_password_expired) {
                            $this->_redirect('auth/change-password');
                            return;
                        }
                        $this->_doRedirect($user);
                        return;
                    } else {
                        $this->_doFailure($result->getIdentity());
                    }
                }
            }
            $this->_redirect('/');
        }
    
        public function changePasswordAction()
        {
            if ($this->_request->isPost()) {
                $username = $this->_auth->getIdentity()->username;
                $formData = $this->_request->getParams();
    
                if (empty($formData['password'])
                    || empty($formData['new_password'])
                    || empty($formData['confirm_password'])
                ) {
                    $this->_flashError('Password cannot be blank.');
                    $this->_redirect('auth/change-password');
                } elseif ($formData['new_password'] !== $formData['confirm_password']) {
                    $this->_flashError('Password and confirmation do not match.');
                    $this->_redirect('auth/change-password');
                } else {
                    $user = new dUser();
                    $result = $user->login($username, $formData['password']);
    
                    if ($result->isValid()) {
    
                        $user->updatePassword($username, $formData['new_password']);
                        $this->_flashNotice('Password updated successfully!');
                        $this->_redirect('/');
                    } else {
                        $this->_flashError('Invalid username or password!');
                        $this->_redirect('auth/change-password');
                    }
                }
    
            }
    
            if ($this->_getParam('force_password_change')) {
                $this->view->notice = 'Your password has expired. You must change your password to continue.';
            }
        }
    
        public function forgotPasswordAction()
        {
            if ($this->_request->isPost()) {
                // Pseudo-random uppercase 6 digit hex value
                $resetCode = strtoupper(substr(sha1(uniqid(rand(),true)),0,6));
    
                Doctrine_Query::create()
                    ->update('dUser u')
                    ->set('u.reset_code', '?', array($resetCode))
                    ->where('u.username = ?', array($this->_getParam('username')))
                    ->execute();
    
                $this->_doMail($this->_getParam('username'), $resetCode);
    
                $this->_flashNotice("Password reset request received.");
                $this->_flashNotice("An email with further instructions, including your <em>Reset Code</em>, has been sent to {$this->_getParam('username')}.");
                $this->_redirect("auth/reset-password/username/{$this->_getParam('username')}");
            }
        }
    
        public function resetPasswordAction()
        {
            $this->view->username = $this->_getParam('username');
            $this->view->reset_code = $this->_getParam('reset_code');
    
            if ($this->_request->isPost()) {
                $formData = $this->_request->getParams();
                if (empty($formData['username']) || empty($formData['reset_code'])) {
                    $this->_flashError('Username or reset code cannot be blank.');
                    $this->_redirect('auth/reset-password');
                } elseif ($formData['new_password'] !== $formData['confirm_password']) {
                    $this->_flashError('Password and confirmation do not match.');
                    $this->_redirect('auth/reset-password');
                } else {
                    $user = new dUser();
                    $result = $user->loginWithResetCode($formData['username'], $formData['reset_code']);
    
                    if ($result->isValid()) {
                        $user->updatePassword($result->getIdentity(), $formData['new_password']);
    
                        $user->fromArray((array) $this->_auth->getIdentity());
    
                        $this->_flashNotice('Password updated successfully!');
                        $this->_doRedirect($user);
                    } else {
                        $this->_doFailure($result->getIdentity());
                        $this->_redirect('auth/reset-password');
                    }
                }
            }
        }
    
        protected function _doRedirect($user)
        {
            $this->_helper->Redirector->gotoUserDefault($user);
        }
    
        protected function _flashError($message)
        {
            $this->_errorMessenger->addMessage($message);
        }
    
        protected function _flashNotice($message)
        {
            $this->_noticeMessenger->addMessage($message);
        }
    
        protected function _doFailure($username)
        {
            $user = Doctrine_Query::create()
                ->from('dUser u')
                ->select('u.is_locked')
                ->where('u.username = ?', array($username))
                ->fetchOne();
    
            if ($user->is_locked) {
                $this->_flashError('This account has been locked.');
            } else {
                $this->_flashError('Invalid username or password');
            }
        }
    }
    
        2
  •  2
  •   ukuser    12 年前

    或者,您可以使用以下内容:

      $request->setParam('skippredispatch',true);
      $this->_forward('index');
    

    在你的控制器里然后

    // If overwriting jump the pre-dispatchy bits
    if ($request->getParam('skippredispatch')){
      $request->setParam('skippredispatch',null);
      return;
    }
    

    有效地跳过了predipatch循环,这看起来工作正常。

        3
  •  1
  •   chelmertz user1604064    14 年前

    这个过程可以在任何操作中进行,但是为什么不在LoginController中进行Logination或IndexAction呢?

    1. 检查登录标识:找到了吗?重定向到索引
    2. 检查post参数:找到了吗?验证、设置标识或设置错误消息
    3. 打印格式

    编辑:可能是太累了,没有意识到真正的问题。我将从每个受登录保护的控制器中的受保护/私有成员开始,例如 protected $authNeeded = true; ,并在 Zend_Controller_Action::init() . 这可能导致重复的代码,所以另一种选择是只在 AuthNeededController 所有受登录保护的控制器扩展。