The right MVC event to tie into for authorization

For authorization, I originally followed the example from Oleg’s book.

He ties his authorization (page protection) method into EVENT_DISPATCH.

The problem I ran into with this is that the controller gets built, which requires forms to be built, which requires custom elements and validators to be built. This seems like a waste and possibly a security risk.

In slack, mwop pointed out that Apigility does authorization late in EVENT_ROUTE. Sure enough, the docs say:

Authorization happens post-route, but before dispatch of the requested service. This is what allows zf-mvc-auth to be able to determine if a particular identity has access to the requested resource without having to start the initialization dispatch of any particular controller in the application.

That makes a lot of sense and matches what I saw.

Problem is, I want to redirect to a particular route upon failure. As per Oleg’s example, I do this:

return $controller->redirect()->toRoute('login');

But, during EVENT_DISPATCH, the controllers aren’t up and running so this doesn’t work.

So, upon authorization failure, am I supposed to craft my own Response, or alter the $event somehow?

And… being my own best friend, here’s what I came up with that seems to be kosher:

    // authorization is required for this request so redirect to login page
    $headers = new Headers();
    $headers->addHeaderLine('Location', '/login');
    $response = new Response();
    $response->setStatusCode(302);
    $response->setHeaders($headers);
    $event->stopPropagation();
    $event->setResponse($response);
    return $response;

Brutal critiques welcome.

What I am doing is in my Module.php onBootstrap() I attach a listener to EVENT_ROUTE, which listener does a two-step thing: check authentication followed by authorization and if either check fails, guess what:

    $response = $event->getResponse();
    $baseUrl = $event->getRequest()->getBaseurl();
    $response->getHeaders()
        ->addHeaderLine('Location', $baseUrl.'/login');
    $response->setStatusCode(303);
    $response->sendHeaders();
    return $response;

which looks quite similar to your own approach, doesn’t it. Which makes me feel warm and fuzzy and validated because you guys are a lot more advanced with this stuff than I am. So, sorry, no brutal critique here.

:grinning:

Actually I was unaware of $event->setResponse($response); I might have to steal that.