andrej-griniuk/cakephp-two-factor-auth

CakePHP 身份验证组件和两步验证提供者

4.0.0 2024-06-19 14:57 UTC

This package is auto-updated.

Last update: 2024-09-19 15:34:42 UTC


README

Build Status codecov License

为 CakePHP 提供两步验证功能的 TwoFactorAuth 插件

此插件使用 RobThree/TwoFactorAuth 库提供两步验证功能。基本上,它的工作方式类似于 CakePHP 的 FormAuthenticate。在提交正确的用户名/密码后,如果用户设置了 secret 字段,将要求用户输入一次性代码。 注意:它只提供验证提供者和组件,并不处理用户的注册、管理等问题。

要求

  • CakePHP 5.0+(对于 CakePHP <3.7,使用 ^1.3 版本;对于 CakePHP 3.x,使用 ^2.0 版本;对于 CakePHP 4.x,使用 ^3.0 版本)

安装

您可以使用 Composer 将此插件安装到您的 CakePHP 应用程序中。

composer require andrej-griniuk/cakephp-two-factor-auth

用法

首先,您需要将 secret 字段添加到您的用户表中(字段名可以根据 TwoFactorAuth.Form 验证器配置更改为其他名称)。

ALTER TABLE `users` ADD `secret` VARCHAR(255) NULL;

其次,您需要在 Application.php 中加载此插件

$this->addPlugin('TwoFactorAuth');

或者,执行以下行

bin/cake plugin load TwoFactorAuth

您可以在这里查看默认配置值,并了解它们的意义这里。要覆盖它们,请将它们作为 TwoFactorForm 验证器值传递。

然后,您需要在 Application.php 中设置身份验证,就像您通常那样,但使用 TwoFactorForm 验证器而不是 Form,例如:

class Application extends BaseApplication implements AuthenticationServiceProviderInterface
{
    public function bootstrap(): void
    {
        // Call parent to load bootstrap from files.
        parent::bootstrap();

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

    public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
    {
        // Various other middlewares for error handling, routing etc. added here.

        // Create an authentication middleware object
        $authentication = new AuthenticationMiddleware($this);

        // Add the middleware to the middleware queue.
        // Authentication should be added *after* RoutingMiddleware.
        // So that subdirectory information and routes are loaded.
        $middlewareQueue->add($authentication);

        return $middlewareQueue;
    }

    public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
    {
        $service = new AuthenticationService();
        $service->setConfig([
            'unauthenticatedRedirect' => '/users/login',
            'queryParam' => 'redirect',
        ]);

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

        // Load the authenticators, you want session first
        $service->loadAuthenticator('Authentication.Session');
        $service->loadAuthenticator('TwoFactorAuth.TwoFactorForm', [
            'fields' => $fields,
            'loginUrl' => '/users/login'
        ]);

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

        return $service;
    }
}

接下来,在 AppController 中加载 AuthenticationTwoFactorAuth 组件

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

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

一旦将中间件应用到您的应用程序中,您就需要一种方式让用户登录。一个简单的 UsersController 可能如下所示

class UsersController extends AppController
{
    public function beforeFilter(\Cake\Event\EventInterface $event)
    {
        parent::beforeFilter($event);

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

    public function login()
    {
        $result = $this->Authentication->getResult();
        if ($result->isValid()) {
            // If the user is logged in send them away.
            $target = $this->Authentication->getLoginRedirect() ?? '/home';

            return $this->redirect($target);
        }

        if ($this->request->is('post') && !$result->isValid()) {
            if ($result->getStatus() == \TwoFactorAuth\Authenticator\Result::TWO_FACTOR_AUTH_FAILED) {
                // One time code was entered and it's invalid
                $this->Flash->error('Invalid 2FA code');

                return $this->redirect(['action' => 'verify']);
            } elseif ($result->getStatus() == \TwoFactorAuth\Authenticator\Result::TWO_FACTOR_AUTH_REQUIRED) {
                // One time code is required and wasn't yet entered - redirect to the verify action 
                return $this->redirect(['action' => 'verify']);
            } else {
                $this->Flash->error('Invalid username or password');
            }
        }
    }

    public function logout()
    {
        $this->Authentication->logout();

        return $this->redirect(['action' => 'login']);
    }

    public function verify()
    {
        // This action is only needed to render a vew with one time code form
    }
}

verify.php 可能如下所示

<div class="users form content">
    <?= $this->Form->create(null, ['url' => ['action' => 'login']]) ?>
    <fieldset>
        <legend><?= __('Please enter your 2FA code') ?></legend>
        <?= $this->Form->control('code') ?>
    </fieldset>
    <?= $this->Form->button(__('Continue')); ?>
    <?= $this->Form->end() ?>
</div>

基本上,它的工作方式与 CakePHP 的 Authentication.Form 验证器相同。在输入正确的用户名/密码组合后,如果用户设置了 secret 字段(可以通过 TwoFactorAuth.TwoFactorForm 配置进行覆盖),则会被重定向到 verify 动作,在该动作中,要求用户输入一次性代码。此操作没有逻辑,它只渲染需要提交到 loginAction 的表单,同时设置 code 字段。

您可以通过 $this->TwoFactorAuth->getTfa() 或直接在 TwoFactorAuth 组件上调用一些方法来从您的控制器访问 RobThree\Auth\TwoFactorAuth 实例。例如,您可以生成用户的密钥并获取其 QR 码数据 URI 的方式如下

$secret = $this->TwoFactorAuth->createSecret();
$secretDataUri = $this->TwoFactorAuth->getQRCodeImageAsDataUri('CakePHP:user@email.com', $secret);

然后在视图中显示它

<img src="<?= $secretDataUri ?>" />

请参阅库页面以获取完整文档:https://github.com/RobThree/TwoFactorAuth

错误 & 反馈

https://github.com/andrej-griniuk/cakephp-two-factor-auth/issues

致谢

https://github.com/RobThree/TwoFactorAuth

许可

版权所有(c)2020,安德烈·格里尼乌克,并许可在MIT许可证下使用。