一起使用 CakePHP 表单和基本身份验证

Using CakePHP Form and Basic Authentication together

我使用 CakePHP 3.8 和 Authentication 1.0 创建了一个简单的测试站点来试用它。我想同时使用 Form 和 Basic 身份验证,因为预期的应用程序将提供 REST 调用。

如果不包含 HttpBasic,站点将正常工作,即显示登录 window。但是,使用 HttpBasic,站点直接进入基本身份验证。

代码直接来自食谱。

我错过了什么?

    public function getAuthenticationService(ServerRequestInterface $request, ResponseInterface $response)
{
    $service = new AuthenticationService();

    $service->setConfig([
            'unauthenticatedRedirect' => '/users/login',
            'queryParam' => 'redirect'
    ]);

    $fields = [
        'username' => 'user',
        'password' => 'password',
    ];

    // Load Identifiers
    $service->loadIdentifier('Authentication.Password', compact('fields'));

    // Load the authenticators
    $service->loadAuthenticator('Authentication.Session');
    $service->loadAuthenticator('Authentication.Form', [
            'fields' => $fields,
            'loginUrl' => '/users/login',
    ]);
    $service->loadAuthenticator('Authentication.HttpBasic');

    return $service;
}

如评论中所述,同时使用表单身份验证器和 HTTP 基本身份验证器效果不会太好,这是因为身份验证服务不会停止执行所有已加载的身份验证器,除非其中之一他们 returns 表示身份验证成功的响应。

这意味着您将始终看到身份验证质询响应,而永远看不到您的登录表单。只有实际的身份验证部分才能在该星座中工作,即直接将您的登录凭据作为表单数据发送到登录端点。

如果您实际上不需要阻止您访问登录表单的基本身份验证质询响应,那么您可以使用不会导致返回质询响应的 custom/extended 身份验证器,这应该像覆盖 \Authentication\Authenticator\HttpBasicAuthenticator::unauthorizedChallenge():

一样简单

src/Authenticator/ChallengelessHttpBasicAuthenticator.php

namespace App\Authenticator;

use Authentication\Authenticator\HttpBasicAuthenticator;
use Psr\Http\Message\ServerRequestInterface;

class ChallengelessHttpBasicAuthenticator extends HttpBasicAuthenticator
{
    public function unauthorizedChallenge(ServerRequestInterface $request)
    {
        // noop
    }
}
$service->loadAuthenticator(\App\Authenticator\ChallengelessHttpBasicAuthenticator::class);

此外,您可能需要添加额外的检查以防您的应用程序使用身份验证组件的 setIdentity() 方法,这会导致身份在会话中持久保存,即使在使用无状态身份验证器时也是如此。如果你不想这样,那么你需要在设置身份之前测试成功的验证器是否是无状态的:

$provider = $this->Authentication->getAuthenticationService()->getAuthenticationProvider();
if (!($provider instanceof \Authentication\Authenticator\StatelessInterface))
{
    $this->Authentication->setIdentity(/* ... */);
}