快速入门

使用 composer 从 CakePHP 项目的根目录(composer.json 文件所在位置)安装插件。

php composer.phar require cakephp/authentication

身份验证插件的版本 3 与 CakePHP 5 兼容。

通过在项目的 src/Application.php 中添加以下语句来加载插件

public function bootstrap(): void
{
    parent::bootstrap();

    $this->addPlugin('Authentication');
}

入门

身份验证插件作为 中间件 与您的应用程序集成。 它也可以用作组件,使未经身份验证的访问更加简单。 首先,让我们应用中间件。 在 src/Application.php 中,将以下内容添加到类导入中

use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Identifier\AbstractIdentifier;
use Authentication\Identifier\IdentifierInterface;
use Authentication\Middleware\AuthenticationMiddleware;
use Cake\Http\MiddlewareQueue;
use Cake\Routing\Router;
use Psr\Http\Message\ServerRequestInterface;

接下来,将 AuthenticationServiceProviderInterface 添加到应用程序的实现接口上

class Application extends BaseApplication implements AuthenticationServiceProviderInterface

然后更新应用程序的 middleware() 方法,使其看起来像

public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
    $middlewareQueue->add(new ErrorHandlerMiddleware(Configure::read('Error')))
        // Other middleware that CakePHP provides.
        ->add(new AssetMiddleware())
        ->add(new RoutingMiddleware($this))
        ->add(new BodyParserMiddleware())

        // Add the AuthenticationMiddleware. It should be
        // after routing and body parser.
        ->add(new AuthenticationMiddleware($this));

    return $middlewareQueue;
}

警告

中间件的顺序很重要。 确保将 AuthenticationMiddleware 放在路由和主体解析器中间件之后。 如果您在使用 JSON 请求登录或重定向不正确时遇到问题,请仔细检查中间件顺序。

AuthenticationMiddleware 在开始处理请求时将在您的应用程序上调用一个钩子方法。 此钩子方法允许您的应用程序定义要使用的 AuthenticationService。 将以下方法添加到 src/Application.php

/**
 * Returns a service provider instance.
 *
 * @param \Psr\Http\Message\ServerRequestInterface $request Request
 * @return \Authentication\AuthenticationServiceInterface
 */
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
    $service = new AuthenticationService();

    // Define where users should be redirected to when they are not authenticated
    $service->setConfig([
        'unauthenticatedRedirect' => Router::url([
                'prefix' => false,
                'plugin' => null,
                'controller' => 'Users',
                'action' => 'login',
        ]),
        'queryParam' => 'redirect',
    ]);

    $fields = [
        AbstractIdentifier::CREDENTIAL_USERNAME => 'email',
        AbstractIdentifier::CREDENTIAL_PASSWORD => 'password'
    ];
    // Load the authenticators. Session should be first.
    $service->loadAuthenticator('Authentication.Session');
    $service->loadAuthenticator('Authentication.Form', [
        'fields' => $fields,
        'loginUrl' => Router::url([
            'prefix' => false,
            'plugin' => null,
            'controller' => 'Users',
            'action' => 'login',
        ]),
    ]);

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

    return $service;
}

首先,我们配置在用户未经身份验证时该怎么做。 接下来,我们附加 SessionForm 身份验证器,它们定义了应用程序将用于对用户进行身份验证的机制。 Session 使我们能够根据会话中的数据来识别用户,而 Form 使我们能够在 loginUrl 上处理登录表单。 最后,我们附加一个 标识符 将用户提供的凭据转换为一个 身份,它代表已登录的用户。

如果配置的身份验证器之一能够验证凭据,则中间件将身份验证服务作为 属性 添加到请求对象中。

接下来,在您的 AppController 中加载 身份验证组件

// in src/Controller/AppController.php
public function initialize()
{
    parent::initialize();

    $this->loadComponent('Authentication.Authentication');
}

默认情况下,组件将要求对 所有 操作进行身份验证。 您可以使用 allowUnauthenticated() 在特定控制器中禁用此行为

// in a controller beforeFilter or initialize
// Make view and index not require a logged in user.
$this->Authentication->allowUnauthenticated(['view', 'index']);

构建登录操作

将中间件应用于应用程序后,您将需要一种方法让用户登录。 请确保您的数据库已使用 教程 中使用的 Users 表结构创建。 首先使用 bake 生成 Users 模型和控制器

bin/cake bake model Users
bin/cake bake controller Users

然后,我们将向您的 UsersController 添加一个基本的登录操作。 它应该看起来像

// in src/Controller/UsersController.php
public function login()
{
    $result = $this->Authentication->getResult();
    // If the user is logged in send them away.
    if ($result->isValid()) {
        $target = $this->Authentication->getLoginRedirect() ?? '/home';
        return $this->redirect($target);
    }
    if ($this->request->is('post')) {
        $this->Flash->error('Invalid username or password');
    }
}

确保您允许访问控制器 beforeFilter() 回调中的 login 操作,如上一节所述,以便未经身份验证的用户能够访问它

// in src/Controller/UsersController.php
public function beforeFilter(\Cake\Event\EventInterface $event)
{
    parent::beforeFilter($event);

    $this->Authentication->allowUnauthenticated(['login']);
}

接下来,我们将为登录表单添加一个视图模板

// in templates/Users/login.php
<div class="users form content">
    <?= $this->Form->create() ?>
    <fieldset>
        <legend><?= __('Please enter your email and password') ?></legend>
        <?= $this->Form->control('email') ?>
        <?= $this->Form->control('password') ?>
    </fieldset>
    <?= $this->Form->button(__('Login')); ?>
    <?= $this->Form->end() ?>
</div>

然后添加一个简单的注销操作

// in src/Controller/UsersController.php
public function logout()
{
    $this->Authentication->logout();
    return $this->redirect(['controller' => 'Users', 'action' => 'login']);
}

我们不需要注销操作的模板,因为我们在最后重定向。

添加密码哈希

为了登录您的用户,他们将需要使用哈希密码。 您可以使用实体 setter 方法在用户更新其密码时自动哈希密码

// in src/Model/Entity/User.php
use Authentication\PasswordHasher\DefaultPasswordHasher;

class User extends Entity
{
    // ... other methods

    // Automatically hash passwords when they are changed.
    protected function _setPassword(string $password)
    {
        $hasher = new DefaultPasswordHasher();
        return $hasher->hash($password);
    }
}

现在,您应该能够转到 /users/add 并注册一个新用户。 注册后,您可以转到 /users/login 并使用您新创建的用户登录。

进一步阅读