【问题标题】:How to correctly throw an UnauthenticatedException in Cakephp 4?如何在 Cakephp 4 中正确抛出 UnauthenticatedException?
【发布时间】:2022-01-22 09:03:25
【问题描述】:

我在 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)在返回中生成responseJSON 而不是UnauthenticatedException

如何使它与UnauthenticatedException 一起工作?

【问题讨论】:

  • 检查响应到底是什么(例如使用浏览器的网络控制台)...我猜这是一个重定向,这意味着您已经配置了中间件的unauthenticatedRedirect 选项。
  • @ndm 你是对的,这似乎是一个重定向,我在Application.php 中有'unauthenticatedRedirect' => Router::url('/admin/users/login'),... 我该怎么做才能让它像UnauthorizedException 这样的常规异常一样工作例如?

标签: php authentication cakephp cakephp-4.x


【解决方案1】:

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

如果您需要同时支持 HTML 和 JSON 请求/响应,那么您可以例如动态配置,分别根据当前请求配置unauthenticatedRedirect 选项,例如在您的@ 987654323@ 方法做一些类似的事情:

$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',
    ]);
}

作为手动评估标头的替代方法,要求 request\Cake\Http\ServerRequest 的实例并使用其 is() 方法:

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

另请注意,默认情况下,身份验证组件将要求身份存在并相应地引发异常,您不必自己这样做。

【讨论】:

  • $isJsonRequest 始终是false...当我调试$request->getHeader('Accept') 它返回["application/json, text/javascript, */*; q=0.01"]。如何检查请求标头中的application/json
  • @Oliv 我错误地认为底层请求实现将提供已经解析的接受标头值。我已经更新了我的答案。
  • 谢谢@ndm,现在我没有重定向了,但奇怪的是errorThrown 现在是Unauthorized 而不是Unauthenticated...
  • @Oliv HTTP状态消息没有Unauthenticated,只有Unauthorized,属于401错误,就是未认证异常映射到的。
  • 嗯...好的...目标是获得比UnauthorizedException 更具体的UnauthenticatedException,尤其是重新加载页面以访问登录页面...太糟糕了。无论如何谢谢;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-18
  • 2019-01-03
  • 1970-01-01
  • 2021-12-09
  • 2018-09-24
  • 1970-01-01
  • 2018-07-07
相关资源
最近更新 更多