brackets / 验证
为 Laravel 提供的双因素认证(2FA)和基于代码的动作验证(短信或电子邮件)
Requires
- php: ^7.3|^8.0
- illuminate/console: ^8.0
- illuminate/database: ^8.0
- illuminate/events: ^8.0
- illuminate/http: ^8.0
- illuminate/routing: ^8.0
- illuminate/support: ^8.0
- nesbot/carbon: ^2.0
- twilio/sdk: ^6.0
Requires (Dev)
This package is auto-updated.
Last update: 2024-09-25 18:31:39 UTC
README
此包应用于基于代码的动作验证(通常是路由)。
当前包支持两种发送验证码的渠道
- 短信
- 电子邮件
但很容易扩展包以支持自定义渠道。
包还包含一个简单的前端(用户可以输入代码的屏幕 + 默认电子邮件/短信模板),可以轻松覆盖以满足您的用户体验。
包还可以帮助您处理验证的特殊情况 - 双因素认证。
安装
-
composer require brackets/verifications -
php artisan verifications:install
使用方法
实现 Verifiable
首先,您需要一个经过身份验证的用户(即 User 模型),该模型实现 Verifiable 接口并使用 VerifiableTrait。您需要在模型上定义 email 和/或 phone 属性,或者实现访问器方法 getPhoneAttribute()/getEmailAttribute()。
注意:如果您需要将 phone_number/email 属性插入到您的 user 表中,可以使用 artisan 命令 verifications:add-email {table-name} 和/或 verifications:add-phone {table-name}。
配置
然后您需要定义一个需要验证的操作。
这可以通过配置文件 /config/verifications.php 实现。
'enabled' => env('VERIFICATION_ENABLED', true), // you can enable/disable globally (i.e. disabled for tests/dev env) 'actions' => [ 'my-action' => [ 'enabled' => true, // you can enable/disable single action 'channel' => 'sms', // currently: sms, email 'form_template' => 'brackets/verifications::verification', // blade name with namespace used for verification code form 'expires_in' => 15, // specifies how many minutes does it take to require another code verification for the same action 'expires_from' => 'verification', // one of: 'last-activity' or 'verification', specifies what triggers the expiration (see expires_in) 'code' => [ 'type' => 'numeric', // specifies the type of verification code, can be one of: 'numeric' or 'string' 'length' => 6, // specifies the verification code length, defaults to 6 'expires_in' => 10, // specifies how many minutes is the code valid ] ] ]
GET 请求验证
通常,您使用此包来保护应用程序的一些特定区域的入口。这可以通过使用 VerificationMiddleware 中间件保护所有路由来实现。
Route::middleware('verifications.verify:{my-action}')
示例
假设我们想验证秘密 money-balance 屏幕。
在您的配置中定义操作
'enabled' => env('VERIFICATION_ENABLED', true), 'actions' => [ 'money-balance' => [ 'enabled' => true, 'channel' => 'sms', 'form_template' => 'brackets/verifications::verification', 'expires_in' => 15, 'expires_from' => 'verification', 'code' => [ 'type' => 'numeric', 'length' => 6, 'expires_in' => 10, ] ] ]
并保护路由
Route::get('/{account}/money-balance', 'MoneyController@moneyBalance') ->name('money-balance') ->middleware('verifications.verify:money-balance');
当用户尝试访问 /{account}/money-balance URL 时,他将被重定向到验证屏幕,需要提供发送给他的代码。
POST 请求验证
验证 POST 动作有点棘手,因为用户不能被重定向回 POST 请求(这是技术上不可能的)。
当然,您可以在用户验证后允许对某些 POST 动作的访问。一旦他完成了验证,一切都会对他顺畅。
您应该始终创建一个显示用户可以执行操作的屏幕的 GET 路由,并保护此 GET 路由(这意味着保护用户可以执行 POST 操作的区域入口)。在这种情况下,用户永远不会遇到需要点击同一操作两次的奇怪行为。
您有两个选择
- 或者确保用户在执行 POST 操作之前始终在某个 GET 路由上验证(因此限制可以执行 POST 操作的区域的入口),
- 或者使用一些方便的 JavaScript 创建一个虚拟屏幕,在加载时自动运行代表用户的 POST 请求,这样他就不必点击两次
使用哪种选项取决于您的具体用例。但通常,如果操作需要用户向表单输入数据,则 showForm GET 路由应该始终受到保护等。
示例
让我们继续使用MoneyApp示例,但现在我们想要保护money-withdraw动作。
保护POST路由的方法非常相似。
Route::post('/{account}/money-withdraw', 'MoneyController@moneyWithdraw') ->name('money-withdraw') ->middleware('verifications.verify:money-withdraw');
这肯定可以防止未验证用户提取资金。但这并没有解决重定向问题。让我们来解决它。
如果我们仔细想想,我们实际上想要保护的是资金提取功能的GET路由,而不仅仅是最终的提交按钮。
所以让我们添加一个GET路由
Route::get('/{account}/money-withdraw', 'MoneyController@moneyWithdrawForm') ->name('money-withdraw-form') ->middleware('verifications.verify:money-withdraw'); Route::post('/{account}/money-withdraw', 'MoneyController@moneyWithdraw') ->name('money-withdraw') ->middleware('verifications.verify:money-withdraw');
方法moneyWithdrawForm会在提交时显示一个表单,该表单会执行POST到/{account}/money-withdraw。但在GET路由中,用户已经进行了验证,所以他的用户体验将会很流畅。
提示:当然,你可以为整个路由组添加中间件
Route::middleware(['verifications.verify:money-balance'])->group(static function () { Route::get('/{account}/money-balance', 'MoneyController@moneyBalance') ->name('money-balance'); Route::get('/{account}/money-withdraw', 'MoneyController@moneyWithdrawAutoConfirmator') ->name('money-withdraw-auto-confirmator'); Route::post('/{account}/money-withdraw', 'MoneyController@moneyWithdraw') ->name('money-withdraw'); // ... });
高级定制用例
在某些场景下,你可能想在某些动作上使用验证并进行进一步定制(例如,只有当满足某些其他条件时才进行验证,或为POST动作验证提供自定义的redirectTo方法)。你可以使用验证外观(Verification facade)在你的控制器中手动运行验证,提供一个闭包,该闭包只有在验证成功后才会运行。
public function postDownloadInvoice(Invoice $invoice) { // this code will run on the attempt before the verification and then again, after the successful verification if (!$invoice->isPublished()) { throw new InvoiceNotPublishedException(); } return Verification::verify('download-invoice', // name of the action '/invoices', // URL user will be redirect after verification (he must click to download the invoice again manually :( function () use ($invoice) { // on the other hand this code will run only once, after the verification return $invoice->download(); }); }
注意,即使在当前场景下,你也需要在POST之前保护GET路由,否则用户将无法被重定向到验证提示屏幕,他将无法继续操作。
定制视图
要自定义默认的blade视图,你只需要使用以下命令发布它们
php artisan vendor:publish --provider="Brackets\Verifications\VerificationServiceProvider" --tag="views"
条件验证
在某些情况下,你可能希望为用户提供一个选项,让他们选择是否应该验证某些特定动作。或者你可能希望允许具有某些特定角色/权限的用户在某些特定动作上跳过验证。在这些情况下,你只需要定义严格命名的isVerificationRequired(string $action)方法。
示例
class User extends Authenticatable implements Verifiable { use VerifiableTrait; // ... public function isVerificationRequired($action) { // allow super admin to all actions if ($this->hasRole('Admin') { return false; } if ($action == 'withdraw-money') { // allow withdraw-money action to be optional (i.e. user can set it in their profile) if (!$this->withdraw_monoey_requires_verification) { return false; } } return true; }
双因素认证
此包的使用有一个特殊用例是双因素认证。
想象一下简单的场景,其中所有用户都需要进行双因素认证。
首先,将新的2FA动作添加到配置中
'actions' => [ '2FA' => [ 'enabled' => true, 'channel' => 'sms', 'expires_in' => 15, 'expires_from' => 'last_activity', 'code' => [ // ... ], ], ]
然后保护所有你的路由
Route::middleware([‘verifications.verify:2FA’])->group(function() { // all your routes goes here })
通道
该包提供了两个默认通道 - 邮件和短信。
邮件
该包使用Laravel的默认邮件外观来发送邮件,所以请确保正确配置。
短信
该包提供了一个短信提供商 - Twilio。
要使用Twilio,你只需要在你的.env文件中提供这些变量
TWILIO_SID="INSERT YOUR TWILIO SID HERE"
TWILIO_AUTH_TOKEN="INSERT YOUR TWILIO TOKEN HERE"
TWILIO_NUMBER="INSERT YOUR TWILIO NUMBER IN [E.164] FORMAT"
查看这篇博客文章以获取有关Twilio集成的更多信息。
安全
如果你发现任何安全相关的问题,请通过电子邮件pavol.perdik@brackets.sk联系,而不是使用问题跟踪器。
致谢
许可证
MIT许可证(MIT)。有关更多信息,请参阅许可证文件。