如何在 Cakephp 4 中正确抛出 UnauthenticatedException?

How to correctly throw an UnauthenticatedException in Cakephp 4?

我在 cakephp 4 中使用插件 Authentication 2。

我想在用户未登录和 ajax 请求的情况下抛出 UnauthenticatedException目标是捕获 JSON 中的异常。

这是我来自服务器的代码:

// in src/Controller/Admin/AdminController.php
use Authentication\Authenticator\UnauthenticatedException;

class AdminController extends AppController {

    public function initialize(): void
    {
        parent::initialize();
        $this->loadComponent('Authentication.Authentication');
    }

    public function beforeFilter(EventInterface $event)
    {
        parent::beforeFilter($event);

        // The server receives an ajax request and the user is not logged in (any more), an UnauthenticatedException is thrown
        if ($this->request->is('ajax') && $this->request->getAttribute('identity') === null) {
            throw new UnauthenticatedException('Please log in');
        }
    }

}

这是我从客户那里得到的代码:

$.ajax({
    dataType: 'json';
    type: 'POST',
    data: $(form).serialize(),
    // [...]
})
// [...]
.fail(function (jqXHR, textStatus, errorThrown) {
    console.log(jqXHR.responseJSON); // There's no responseJSON in jqXHR...
    alert("(" + errorThrown + ")" + jqXHR.responseJSON.message);
    if (errorThrown == 'Unauthenticated') {
        location.reload();
    }
});

问题是 jqXHR 中没有 responseJSON

为什么任何其他异常(例如我之前使用的 UnauthorizedException)在 return 中生成 responseJSON 而不是 UnauthenticatedException

如何让它与 UnauthenticatedException 一起工作?

身份验证中间件默认re-throws未经身份验证的异常,即除非您配置unauthenticatedRedirect选项,否则它将相应地将这些异常转换为重定向。

如果需要同时支持HTML和JSONrequests/responses,那么可以比如动态配置,分别配置unauthenticatedRedirect 选项,基于当前请求,例如在您的 Application::getAuthenticationService() 方法中执行以下操作:

$service = new AuthenticationService();

$accepts = array_map('trim', explode(',', $request->getHeaderLine('Accept')));
$isJsonRequest = in_array('application/json', $accepts, true);

if (!$isJsonRequest) {
    // service config for non-JSON requests
    $service->setConfig([
        'unauthenticatedRedirect' => /* ...*/,
        'queryParam' => 'redirect',
    ]);
}

或者手动评估 header,要求 request 成为 \Cake\Http\ServerRequest 的实例并使用它的 is() 方法:

assert($request instanceof \Cake\Http\ServerRequest);
if (!$request->is('json')) {
    $service->setConfig([
        'unauthenticatedRedirect' => [/* ...*/],
        'queryParam' => 'redirect',
    ]);
}

另请注意,身份验证组件默认要求提供身份并相应地抛出异常,您不必自己执行此操作。