Redirecting
As mentioned in the comments, if the redirect doesn't happen, then you've likely not imported the (correct) FQN for that exception, it should be:
\Authorization\Exception\ForbiddenException
Using this in the unauthorizedHandler
config of the authorization middleware should work fine using the example shown in the docs, eg:
$middlewareQueue->add(
new \Authorization\Middleware\AuthorizationMiddleware($this, [
'unauthorizedHandler' => [
'className' => 'Authorization.Redirect',
'url' => '/users/login',
'queryParam' => 'redirectUrl',
'exceptions' => [
\Authorization\Exception\ForbiddenException::class,
],
],
])
);
This would cover the redirect part. If you also want to show a message to the user, then you pretty much have two options, either redirect to a page that has a more or less hardcoded message, or use your own redirect handler and set a flash message.
Setting a flash message
A simple example for the latter could look like this:
<?php
// in src/Middleware/UnauthorizedHandler/FlashRedirectHandler.php
namespace App\Middleware\UnauthorizedHandler;
use Authorization\Exception\Exception;
use Authorization\Middleware\UnauthorizedHandler\RedirectHandler;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class FlashRedirectHandler extends RedirectHandler
{
public function handle(
Exception $exception,
ServerRequestInterface $request,
array $options = []
): ResponseInterface
{
$response = parent::handle($exception, $request, $options);
$message = sprintf(
'You are not authorized to access the requested resource `%s`.',
$request->getRequestTarget()
);
/** @var \Cake\Http\FlashMessage $flash */
$flash = $request->getAttribute('flash');
$flash->error($message);
return $response;
}
}
'unauthorizedHandler' => [
'className' => \App\Middleware\UnauthorizedHandler::class,
// ...
],
The flash message class has been introduced with CakePHP 4.2, in earlier versions you would have to manually write into the session, which isn't overly nice:
/** @var \Cake\Http\Session $session */
$session = $request->getAttribute('session');
$messages = (array)$session->read('Flash.flash', []);
$messages[] = [
'message' => $message,
'key' => 'flash',
'element' => 'flash/error',
'params' => [],
];
$session->write('Flash.flash', $messages);
ps
You should find a better way to obtain the groups of the identity, IMHO having dependencies like sessions in your policies is destined to cause you trouble further down the road.
Ideally the identity should hold the groups that it belongs to, so that you can simply do:
return in_array('site_admin', $user['groups'], true);
See CakePHP Authentication Plugin Identity Associations