【问题标题】:Zend _forward doesn't work after failed authentication (Zend Framework 1)Zend _forward 在身份验证失败后不起作用(Zend Framework 1)
【发布时间】:2013-10-07 11:02:55
【问题描述】:

在用户授权失败后,我想将他们转发回登录页面。目前 _forward 方法会导致 Zend 挂起并给出超时错误(超过 30 秒)。

登录页面的代码处理登录和注册表单,并转发给授权控制器:

public function indexAction() {

    if ($this->_request->isPost()) {
        $formData = $this->_request->getPost();

        if (array_key_exists('signUp', $formData)) {
            $authAction = 'signup';
            $form = 'signupForm';
        } elseif (array_key_exists('logIn', $formData)) {
            $authAction = 'login';
            $form = 'loginForm';
        }

        if ($this->$form->isValid($formData)) {
            $this->_forward($authAction, 'user-auth', null, $formData);
        } else {
            $this->$form->populate($formData);
        }
    }
}

这工作正常并成功重定向到身份验证控制器。 auth 控制器的登录动作里面的代码是这样的:

public function loginAction() {
    $formData = $this->_request->getPost();

    $authAdapter = new My_Auth_Adapter();
    $authAdapter->setTableName('user')
                ->setIdentity($formData['username'])
                ->setCredential($formData['password'])
                ->setIdentityColumn('username')
                ->setCredentialColumn('password');
    $result = $authAdapter->authenticate();

    if ($result->isValid()) {
        // success, all good
    } else {
        $this->_forward('index', 'login', 'default', $formData);
    } 
}

我们很好地到达这里,成功的授权按预期工作。然而,在我的 else 语句中,将另一个转发回原始登录控制器(我希望填充用户名并回发错误消息)会导致程序挂起,尽管重定向工作正常。

我认为这可能是因为登录控制器正在重新检测发布数据并且我陷入了无限循环,但是删除 $formData 作为转发的最后一个参数并没有改变任何东西。

我也试过 $formData['errMsg'] = 'whatever' 上面的转发,然后检查密钥是否存在或是否在登录控制器中设置,但这也不会改变任何事情。

有趣的是,我收到的超时错误引用了 Auth DbTable 适配器:

Fatal error: Maximum execution time of 30 seconds exceeded in /Applications/MAMP/MampServer/mysite/library/Zend/Auth/Adapter/DbTable.php on line 174

对可能发生的事情有什么想法吗?

【问题讨论】:

    标签: php zend-framework


    【解决方案1】:

    我认为你在loginAction()indexAction() 之间无限循环。

    查看对 forward()redirect() 操作助手的调用之间的区别。前者,forward() 在内部将更改 $request->isDispatched() == false - 这意味着前端控制器将执行目标控制器操作 没有新的 HTTP 请求。

    这样的结果是$this->_request->isPost() 将永远是true,因此$this->$form->isValid($formData) 也将是真的,这意味着你在绕圈子。

    我知道下面的方法与您的方法非常不同,但我相信它是 Zend 1 控制器的更传统的关注点分离。

    // ... SomeController.php
    
      public function getLoginForm();
    
      public function getSignupForm();
    
      protected function authenticate($username, $password) 
      {
        $authAdapter = new My_Auth_Adapter();
        $authAdapter->setTableName('user')
                    ->setIdentity($username)
                    ->setCredential($password)
                    ->setIdentityColumn('username')
                    ->setCredentialColumn('password');
        $result = $authAdapter->authenticate();
    
        return ($result->isValid()) ? true : false;
      }
    
      public function indexAction()
      {
        $form = $this->getLoginForm();
        $request = $this->getRequest();
    
        if ($request->isPost()) {
          if ($form->isValid($request->getPost())) {
    
            if ($this->authenticate($form->getValue('username'), $form->getValue('username'))) {
              $this->redirect('/members'); // Successfully logged in
            }
          }
        }
        $this->view->form = $form;
      }
    
      public function signupAction()
      {
        // stuff only for signups! 
      }
    

    编辑 详细说明:forward() 是一个控制器动作助手。它的工作只是修改Zend_Controller_Request_Http 实例。 Zend_Controller_Request_Http 类是在控制器中调用 $this->getRequest() 时返回的类。

    Request 实例封装了对$_POST$_GET 的所有访问,然后将其作为值存储在对象中。诸如$request->setParam('someparam', 123) 之类的调用设置或获取这些值,而不是标准的直接访问$_POST['someparam']$_GET['someparam']

    特殊情况是值modulecontrolleractiondispatched。这些是 Zend_Controller_FrontDispatcher 在尝试确定要实例化 的正确控制器和执行 的操作方法时使用的密钥。

    dispatch loop 工作原理的简化示例:

    while(! $request->isDispatched()) {
    
      $request->setDispatched(true);
    
      // If at any point here we change setDispatched(true)
      // perhaps in a controller action with a call to forward()
      // then the whole dispatch loop will be called again
      // perhaps creating a different controller
    
      $controllerName = $request->getControllerName();
      $actionName = $request->getActionName();
    
      $controller = new $controllerName();
      $controller->$actionName();
    
    }
    

    【讨论】:

    • 谢谢 - 这个解决方案比我尝试做的更有意义。但是,如果您可以详细说明一件事-我很困惑,如果 forward 方法不重置 HTTP 标头,您如何能够将参数附加到它?或者它是一次设置,这是一种交易?
    • @AdrianNorman 我已经更新了我的答案,希望它有意义。最好的办法是查看控制器和调度程序的代码以获得更好的想法。
    • 非常感谢您的详细说明 - 就 Zend_Controller_Request_Http 对象为我澄清了很多。
    【解决方案2】:

    在 else 块中:

    $this->_redirect($this->url(array('login' => $formData['username'], 'nameOfYourRoute'));
    

    向您的路由添加了一个新的获取变量“登录”,并使用此变量填充您的表单登录。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-04
      • 1970-01-01
      • 2012-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多