Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Magento: Extending Customer Account Controller to add actions to the forgot password steps

We are trying to add a couple of actions to the AccountController to add another action after the forgotpasswordpost action. The problem is if we add the action to the preDispatch logict to make sure you don't have to be logged in it still redirects back to the login page.

public function preDispatch()
    {
        // a brute-force protection here would be nice

        parent::preDispatch();

        if (!$this->getRequest()->isDispatched()) {
            return;
        }

        $action = $this->getRequest()->getActionName();
        if (!preg_match('/^(create|login|logoutSuccess|forgotpassword|forgotpasswordpost|confirm|confirmation|newactionhere)/i', $action)) {
            if (!$this->_getSession()->authenticate($this)) {
                $this->setFlag('', 'no-dispatch', true);
            }
        } else {
            $this->_getSession()->setNoReferer(true);
        }
    }

This doesn't work because we are calling the parent first which runs this as well but of course the preg_match doesn't match and it runs the authenticate method which runs the method $action->getResponse()->setRedirect($url) which of course sets the header and when it gets back to our code it doesn't matter and then redirects.

We could just remove the call to the parent but I am not sure that is the best approach since the parent calls its parent as well which runs some stuff to set the layout area and then also calls the parent method. I was thinking to just call the parent wtih Mage_Core_Controller_Front_Action but wasn't sure that was the right approach either.

like image 389
dan.codes Avatar asked Jan 22 '23 09:01

dan.codes


2 Answers

So this is what we did, we got the flag and checked if the action had the flag of no-dispatch. then we unset it, cleared the header and reset the response code.

public function preDispatch()
{
    // a brute-force protection here would be nice

    parent::preDispatch();

    $action = $this->getRequest()->getActionName();

    // The parent preDispatch call will set:
    // 1. the 'no-dispatch' flag and set a
    // 2. a 'Location' header for a 302 redirect to the login page
    //    for any actions which are not on the list.
    // 3. a HTTP Response Code of 302 (temporary redirect).
    // We add additional actions securityquestion and securityquestionpost in our override below, but
    // we need to undo the settings which get set by the call to the parent above.
    if (preg_match('/^(securityquestion|securityquestionpost)/i', $action))
    {
        $flag = 'no-dispatch';

        if ($this->getFlag($action, $flag))
        {
              unset($this->_flags[$action][$flag]); // Remove the flag to unset it
              $this->getResponse()->clearHeader('Location'); // Remove Location header for redirect
              $this->getResponse()->setHttpResponseCode(200); // Set HTTP Response Code to OK

        }
    }

    if (!$this->getRequest()->isDispatched()) {
        return;
    }


    if (!preg_match('/^(create|login|logoutSuccess|forgotpassword|forgotpasswordpost|confirm|confirmation|securityquestion|securityquestionpost)/i', $action)) {
        if (!$this->_getSession()->authenticate($this)) {
            $this->setFlag('', 'no-dispatch', true);
        }
    } else {
        $this->_getSession()->setNoReferer(true);
    }
}
like image 72
dan.codes Avatar answered Feb 24 '23 20:02

dan.codes


I needed to do something simmilar, I ended up skipping the original implementation of preDispatch of the Mage_Customer_AccountController.

so in my overriding class I have:

public function validActions() { return 'create|login|logoutSuccess|forgotpassword|forgotpasswordpost|confirm|confirmation|mynewaction'; }

public function preDispatch()
{
    //I override this to add my new Action as a valid one.
    //this is also the reason why I call the grand parent and not parent class's preDispatch()
    // becase the default implementation does not enable to simply override the list of valid actions.

    // a brute-force protection here would be nice

    $par = get_parent_class($this);
    $gpar = get_parent_class($par);  
    $gpar::preDispatch();

    if (!$this->getRequest()->isDispatched()) {
        return;
    }

    $action = $this->getRequest()->getActionName();
    if (!preg_match('/^(' . $this->validActions() . ')/i', $action)) {
        if (!$this->_getSession()->authenticate($this)) {
            $this->setFlag('', 'no-dispatch', true);
        }
    } else {
        $this->_getSession()->setNoReferer(true);
    }
}

as you can see I also added a validActions() that returns a pipe separated list of actions so if someone wants to override my own code it will be much easier to add another action.

like image 42
epeleg Avatar answered Feb 24 '23 22:02

epeleg