3

I'm looking through controllers, routes, sections, observers... and I can't find the method for protecting a page from non-logged in customers.

How is this done officially?

I may have found an answer in

vendor/magento/module-customer/etc/frontend/di.xml

If this is the method, could someone explain it to me?

  • Magento protected loggedin pages using dispatch() function of each Controller – Amit Bera Jun 8 '16 at 8:09
3

From what I understood, there's basically two ways Magento does this.

The first one is via a plugin: Magento\Customer\Controller\Plugin\Account declared in etc/frontend/di.xml :

<type name="Magento\Customer\Controller\Plugin\Account">
    <arguments>
        <argument name="allowedActions" xsi:type="array">
            <item name="create" xsi:type="string">create</item>
            <item name="login" xsi:type="string">login</item>
            <item name="logoutsuccess" xsi:type="string">logoutsuccess</item>
            <item name="forgotpassword" xsi:type="string">forgotpassword</item>
            <item name="forgotpasswordpost" xsi:type="string">forgotpasswordpost</item>
            <item name="resetpassword" xsi:type="string">resetpassword</item>
            <item name="resetpasswordpost" xsi:type="string">resetpasswordpost</item>
            <item name="confirm" xsi:type="string">confirm</item>
            <item name="confirmation" xsi:type="string">confirmation</item>
            <item name="createpassword" xsi:type="string">createpassword</item>
            <item name="createpost" xsi:type="string">createpost</item>
            <item name="loginpost" xsi:type="string">loginpost</item>
        </argument>
    </arguments>
</type>
<type name="Magento\Customer\Controller\AbstractAccount">
    <plugin name="customer_account" type="Magento\Customer\Controller\Plugin\Account" />
</type>

Every account related controllers except the Address controllers extend the Magento\Customer\Controller\AbstractAccount abstract controller.

And the plugin uses aroundDispatch to check if the user is logged in or not:

public function aroundDispatch(
    ActionInterface $subject,
    \Closure $proceed,
    RequestInterface $request
) {
    $action = strtolower($request->getActionName());
    $pattern = '/^(' . implode('|', $this->allowedActions) . ')$/i';

    if (!preg_match($pattern, $action)) {
        if (!$this->session->authenticate()) {
            $subject->getActionFlag()->set('', ActionInterface::FLAG_NO_DISPATCH, true);
        }
    } else {
        $this->session->setNoReferer(true);
    }

    $result = $proceed($request);
    $this->session->unsNoReferer(false);
    return $result;
}

As you can see from the di.xml file, the plugin takes a number of arguments which are the actions allowed as a not logged in users.

Then the plugin checks if the action is allowed, if it's not and the user is not logged in then it sets the no dispatch flag so the action is not dispatched and the page can't be accessed:

    if (!preg_match($pattern, $action)) {
        if (!$this->session->authenticate()) {
            $subject->getActionFlag()->set('', ActionInterface::FLAG_NO_DISPATCH, true);
        }
    }

The second way is only affecting the Address related controllers. Every address related controllers extend the abstract controller Magento\Customer\Controller\Address

If you check this controller dispatch() method you can see the following code that checks if the user is logged and if the user is not logged in, it sets the no dispatch flag so the page cannot be accessed:

public function dispatch(RequestInterface $request)
{
    if (!$this->_getSession()->authenticate()) {
        $this->_actionFlag->set('', 'no-dispatch', true);
    }
    return parent::dispatch($request);
}

Regarding the redirection, when the authenticate method is called, it sets the redirect URL to the login page by default:

public function authenticate($loginUrl = null)
{
    if ($this->isLoggedIn()) {
        return true;
    }
    $this->setBeforeAuthUrl($this->_createUrl()->getUrl('*/*/*', ['_current' => true]));
    if (isset($loginUrl)) {
        $this->response->setRedirect($loginUrl);
    } else {
        $arguments = $this->_customerUrl->getLoginUrlParams();
        if ($this->_session->getCookieShouldBeReceived() && $this->_createUrl()->getUseSession()) {
            $arguments += [
                '_query' => [
                    $this->sidResolver->getSessionIdQueryParam($this->_session) => $this->_session->getSessionId(),
                ]
            ];
        }
        $this->response->setRedirect(
            $this->_createUrl()->getUrl(\Magento\Customer\Model\Url::ROUTE_ACCOUNT_LOGIN, $arguments)
        );
    }

    return false;
}
| improve this answer | |
  • What happens when the action isn't allowed? Redirect to login page or home? – LM_Fielding Jun 8 '16 at 8:42
  • 1
    @LM_Fielding see my edited answer – Raphael at Digital Pianism Jun 8 '16 at 8:50
  • Raphael is the $loginUrl parameter where the user is redirected to when they complete authentication? – LM_Fielding Jun 27 '16 at 10:06
  • 1
    @LM_Fielding yes it is – Raphael at Digital Pianism Jun 27 '16 at 10:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.