zegert / cakephp-two-factor-auth
CakePHP 双因素认证组件和提供者
Requires
- php: >=8.1
- cakephp/cakephp: 4.3.*
- robthree/twofactorauth: ^2.1
Requires (Dev)
- phpunit/phpunit: ^10
README
为 CakePHP 提供两因素认证功能的插件
此插件使用 RobThree/TwoFactorAuth 库提供两因素认证功能。基本上,它的工作方式与 CakePHP FormAuthenticate
相似。在提交正确的用户名/密码后,如果用户设置了 secret
字段,将被要求输入一次性的验证码。注意:它只提供认证提供者和组件,不负责用户的注册、管理等。
要求
- CakePHP 4.0+(对于 CakePHP <3.7,使用 ^1.3 版本,对于 CakePHP <4.0,使用 ^2.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()
从控制器访问 RobThree\Auth\TwoFactorAuth 实例,或者直接在 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