andrej-griniuk / cakephp-two-factor-auth
CakePHP 身份验证组件和两步验证提供者
Requires
- php: >=8.1
- cakephp/authentication: ^3.0
- cakephp/cakephp: ^5.0
- robthree/twofactorauth: ^2.1
Requires (Dev)
- phpunit/phpunit: ^10
README
为 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 中加载 Authentication
和 TwoFactorAuth
组件
// 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