Redirect to last visited page after authorization fail

I’m currently using the Authorization plugin. My goal is to redirect all unauthorized requests to the last visited page.

I’ve read the documentation Class ServerRequest | CakePHP 4.4 but can’t find the answer so I’m pretty sure I’m missing something.

I have a “working” solution but maybe someone knows better. Thanks in advance!

AppController.php

public function beforeRender(EventInterface $event)
{
$cookie = new Cookie(‘last_page’, $this->request->getPath());

    $this->response = $this->response->withCookie($cookie);
}

ForbiddenExceptionHandler.php

class ForbiddenExceptionHandler extends RedirectHandler
{
public function handle(Exception $exception, ServerRequestInterface $request, array $options = ): ResponseInterface
{
if ($request instanceof ServerRequest) {

        $request->getFlash()->error(__('Acceso denegado'));

        $last_page = $request->getCookie('last_page') ?? ['prefix' => false, 'controller' => 'Records', 'action' => 'index'];

        $url = Router::url($last_page);

        $response = new Response();
        return $response->withHeader('Location', $url);
    }

    return parent::handle($exception, $request, $options);
}

}

What exactly do you define as last visited page.

Unauthorized requests can come from multiple sources:

  • A logged in user which is not allowed to view a specific page
  • A logged in user which “times out” and gets redirected to the login page due to e.g. a not valid CookieAuth cookie
  • A not logged in user which tries to view a specific page which requires authentication (which basically is not 100% an authorization fail but maybe you want to catch that as well)
  • and maybe some more

Can you maybe explain in more detail which kind of usecase you want to catch so we can provide better support for you.

Thank you for your response.

I just need to handle the first case: “a logged in user which is not allowed to view a specific page” which I would also identify as “any request where the EntityPolicy.php returned false” or "any ForbiddenException".

I think the other two would be called “an unauthenticated request” or a MissingIdentityException

With last visited page I mean “the last place the user visited and was authorized to” therefore creating the cookie in the beforeRender() method is just a partial solution.
I think I should be looking for a method called after any EntityPolicy.php method returns true.

On the other hand, reading the cookie on ForbiddenExceptionHandler class seems correct to me.

I’ll also have this piece of code which might clarify better what I’m trying to achieve.

$authorization = new AuthorizationMiddleware($this, [
‘unauthorizedHandler’ => [
‘className’ => ForbiddenExceptionHandler::class,
‘exceptions’ => ForbiddenException::class,
],
]);

According to Authorization Middleware - 2.x I can use the ‘url’ option but that’s not enough for me.

You can redirect to last page like this:

$this->referer();

I would say you need to write a custom UnauthorizedHandler to achieve what you want.
You can look at the example in the docs where we explain how to show a Flash Message on unauthorized requests.
https://book.cakephp.org/authorization/2/en/middleware.html#add-a-flash-message-after-being-redirected-by-an-unauthorized-request