带有授权插件的 Cakephp 4:授权失败时的自定义错误消息

Cakephp 4 with Authoirzation plugin: Custom errror message when Authorization fails

各位。如果之前有人问过这个问题,我深表歉意,但我很难找到关于这个主题的 任何东西

我在我的应用程序中加载了授权插件,它工作正常,除了用户在未被授权做某事时收到的消息。例如,只允许站点管理员对用户帐户执行任何操作:

public function canAdd(IdentityInterface $user, User $resource)
{
    // Site admins can add users
    $session = Router::getRequest()->getSession();
    $groups = $session->read('groups');
    return in_array('site_admin', $groups);
}    

在 UsersController 中调用 $this->Authorization->authorize($user) 有效,并且禁止没有站点管理员组权限的任何人,但是我如何自定义未经授权的用户看到的错误消息并将他们重定向到其他地方?似乎没有明显的方法可以做到这一点。

重定向

如评论中所述,如果重定向没有发生,那么您可能没有为该异常导入(正确的)FQN,它应该是:

\Authorization\Exception\ForbiddenException

在授权中间件的 unauthorizedHandler 配置中使用它应该可以正常使用文档中显示的示例,例如:

$middlewareQueue->add(
    new \Authorization\Middleware\AuthorizationMiddleware($this, [
        'unauthorizedHandler' => [
            'className' => 'Authorization.Redirect',
            'url' => '/users/login',
            'queryParam' => 'redirectUrl',
            'exceptions' => [
                \Authorization\Exception\ForbiddenException::class,
            ],
        ],
    ])
);

这将涵盖重定向部分。如果您还想向用户显示一条消息,那么您几乎有两个选择,要么重定向到一个或多或少具有硬编码消息的页面,要么使用您自己的重定向处理程序并设置一个 flash 消息。

设置即显消息

后者的一个简单示例如下所示:

<?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,
    // ...
],

CakePHP 4.2 引入了 flash 消息 class,在早期版本中,您必须手动写入会话,这不太好:

/** @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

您应该找到一种更好的方法来获取身份的组ps,恕我直言,在您的策略中具有诸如会话之类的依赖项注定会给您带来麻烦。

理想情况下,身份应该包含它所属的组ps,这样你就可以简单地做:

return in_array('site_admin', $user['groups'], true);