airondev / laravel-2fa
此包允许您在Laravel应用程序中启用双因素认证。它本地存储令牌并通过电子邮件、短信或任何自定义通道通知用户。包括原生条件性检查,以根据已知设备、IP地址或IP位置触发或跳过2FA。
Requires
- php: ^7.3|^7.4|^8.0
This package is auto-updated.
Last update: 2024-09-06 14:58:26 UTC
README
简介
此包允许您非常容易地在Laravel应用程序中启用双因素认证,无需添加中间件或修改路由。它在数据库中存储令牌,并使用独立的表,因此您无需更改users
表。通过邮件、短信或任何自定义通道通知用户令牌。
包括原生条件性检查以触发或跳过2FA:当用户使用已知浏览器、IP地址、IP地理位置或任何自定义规则时,您可以跳过检查。
此包受到了srmklive/laravel-twofactor-authentication包的启发,该包支持Authy 2FA认证。
安装
- 使用Composer安装包
composer require Airondev-agency/laravel-2fa
- 将服务提供者添加到
config/app.php
文件中的providers
数组中
'providers' => [ [...] /* * Package Service Providers... */ Airondev\Laravel2FA\Laravel2FAServiceProvider::class, ],
- 运行以下命令发布资产
php artisan vendor:publish --provider "Airondev\Laravel2FA\Laravel2FAServiceProvider"
- 运行以下命令迁移数据库
php artisan migrate
- 在您的用户模型(例如
App\Models\User.php
)中添加以下行
- 在类声明之前添加以下行
use Airondev\Laravel2FA\TwoFactorAuthenticatable; use Airondev\Laravel2FA\Contracts\TwoFactorAuthenticatableContract;
- 修改类定义以实现
TwoFactorAuthenticatableContract
合同
class User extends Authenticatable implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, TwoFactorAuthenticatableContract
- 添加
TwoFactorAuthenticatable
特质
use Authenticatable, Authorizable, CanResetPassword, TwoFactorAuthenticatable;
-
确保您的用户模型使用了Notifiable特质。
-
您需要通过向
app\Http\Controllers\Auth\LoginController.php
类中添加authenticated
方法来更改登录流程。
<?php namespace App\Http\Controllers\Auth; use Airondev\Laravel2FA\TwoFactorAuth; class LoginController extends Controller { /** [...] **/ /** * The user has been authenticated. * * @param \Illuminate\Http\Request $request * @param mixed $user * @return mixed */ protected function authenticated(Request $request, $user) { # Trigger 2FA if necessary. if (TwoFactorAuth::getDriver()->mustTrigger($request, $user)) { return TwoFactorAuth::getDriver()->trigger($request, $user); } # If not, do the usual job. return redirect()->intended($this->redirectPath()); }
🚀 您也可以使用您最喜欢的简短版本
/** * The user has been authenticated. * * @param \Illuminate\Http\Request $request * @param mixed $user * @return mixed */ protected function authenticated(Request $request, $user) { return TwoFactorAuth::getDriver()->maybeTrigger($request, $user) ?: redirect()->intended($this->redirectPath()); }
就是这样!现在您想自定义视图并查看配置部分。
构建视图
当您发布包资产时,将创建一个新的resources/views/auth/2fa/token.blade.php
文件。您可以根据自己的需求设计此页面,但您必须保留token
表单输入名称,并将表单发送到route('auth.2fa.store')
路由。
您可能注意到一个$reason
变量,它告诉您为什么触发了2FA认证。根据您的应用需求,您可以选择是否向用户显示它。
配置
所有配置都设置在当您发布包时创建的config/laravel-2fa.php
文件中。
内置
首先,您需要选择要应用哪些策略。策略的工作是检查是否必须执行双因素认证,或者是否可以跳过(例如:浏览器是否已知?跳过双因素认证)。
策略在policy
键中定义。规则可以组合,具有优先级顺序。每个策略都会被调用,并告诉驱动程序是否应该触发双因素认证。当策略需要双因素认证时,检查停止,其返回的message
将用作视图中的$reason
(参见构建视图部分)。
如果没有触发任何策略,或者 policy
数组为空,则跳过双因素认证,用户正常登录。
return [ 'policy' => [ 'browser', // first check if we know the browser 'geoip', // if so, check if we know the user ip location // if so, no more rules : skip 2FA. ], ];
内置策略包括:
ℹ️ 需要创建自己的策略?请参阅下方的 自定义策略 部分。
一些策略有额外的设置,这些设置在配置文件中有自我说明。
return [ /* |-------------------------------------------------------------------------- | The 2FA package options. |-------------------------------------------------------------------------- | | Here you may specify the package options, such as policies parameters. | */ 'options' => [ # 2FA token lifetime in minutes. 'token_lifetime' => 10, 'policies' => [ # Can be one of "country", "region", "city", "time_zone". 'geoip' => 'country', # Cookie expiration time in minutes (default 30 days). 'browser' => 30 * 1440, ], ], ];
自定义通知
此包使用 Laravel 的 通知 系统。内置通知 TwoFactorToken
通过邮件将双因素令牌发送给用户。
您可以通过扩展此类来扩展此通知并配置其他通道,例如 短信
<?php namespace App\Notifications; use Airondev\Laravel2FA\Notifications\TwoFactorToken as BaseTwoFactorToken; class TwoFactorToken extends BaseTwoFactorToken { /** * Get the notification's delivery channels. * * @param mixed $notifiable * @return array */ public function via($notifiable) { return [ 'nexmo', ]; } /** * Get the Vonage / SMS representation of the notification. * * @param mixed $notifiable * @return NexmoMessage */ public function toNexmo($notifiable) { return (new NexmoMessage) ->content('Your two-factor token is ' . $this->token) ->from('MYAPP'); } }
您需要更改 notification
配置键以指定您的新通知类
return [ [...] /* |-------------------------------------------------------------------------- | The 2FA notification containing the token. |-------------------------------------------------------------------------- | | Here you may specify an alternative notification to use. | */ 'notification' => \App\Notifications\TwoFactorToken::class, ];
自定义策略
如果您对内置策略不满意,可以覆盖现有策略或创建自己的策略。
所有策略都必须扩展 AbstractPolicy
。
要覆盖现有策略,您可以直接扩展策略类
<?php namespace App\Auth\Policies; use Airondev\Laravel2FA\Policies\IpPolicy as BaseIpPolicy; class IpPolicy extends BaseIpPolicy { /** * Check that the request passes the policy. * If this return false, the 2FA Auth will be triggered. * * @return bool */ public function passes(): bool { # Passes the check if the user didn't activate IpPolicy on his account. if ( ! $this->user->hasTwoFactorAuthActiveForIp()) { return true; } # Else, run the IpPolicy check. return parent::passes(); } /** * The reason sent to the Notification and the frontend view, * to tell the user why the 2FA check was triggered. * * @return string */ public function message(): string { return $this->message ?: __('your account activated 2FA for unknown IP adresses.'); } }
然后,更改设置中的 mapping
数组
return [ [...] 'mapping' => [ [...] 'ip' => \Auth\Policies\IpPolicy::class, ], ];
ℹ️ AbstractPolicy 有 3 个可用属性,您可以在 passes()
方法中用于构建策略检查
/** * The incomming request at login. * * @var \Illuminate\Http\Request */ protected $request = null; /** * The user that just loggued in. * * @var \Airondev\Laravel2FA\Contracts\TwoFactorAuthenticatableContract */ protected $user = null; /** * The login attempt, with UID and IP address data. * * @var \Airondev\Laravel2FA\Models\LoginAttempt */ protected $attempt = null;
创建策略很简单。例如,假设用户可能在其设置中激活 2FA。您可以创建一个策略来验证用户是否激活了 2FA,如果是,则 passes()
方法失败,从而导致触发 2FA 认证
<?php namespace App\Auth\Policies; use Airondev\Laravel2FA\Policies\AbstractPolicy; class ActivePolicy extends AbstractPolicy { /** * Check that the request passes the policy. * If this return false, the 2FA Auth will be triggered. * * @return bool */ public function passes(): bool { return $this->user->hasTwoFactorAuthActive() ? false : true; } /** * The reason sent to the Notification and the frontend view, * to tell the user why the 2FA check was triggered. * * @return string */ public function message(): string { return $this->message ?: __('your account activated the 2FA auth'); } }
您还可以有不同的检查,这些检查会产生不同的 $reason
消息
<?php namespace App\Auth\Policies; use Airondev\Laravel2FA\Policies\AbstractPolicy; class ActivePolicy extends AbstractPolicy { /** * Check that the request passes the policy. * If this return false, the 2FA Auth will be triggered. * * @return bool */ public function passes(): bool { if ($this->user->hasTwoFactorAuthActive()) { $this->message = __('your account activated the 2FA auth'); return false; } if ($this->user->didntSpecifyTwoAuthActive()) { $this->message = __('2FA auth is activated by default'); return false; } if (anyReason()) { return false; // will use the default reason used in message() method. } return true; } /** * The reason sent to the Notification and the frontend view, * to tell the user why the 2FA check was triggered. * * @return string */ public function message(): string { return $this->message ?: __('2FA auth is automatically activated for your account'); } }
创建策略后,您可以在配置文件中使用它
return [ 'policy' => [ \Auth\Policies\ActivePolicy::class, ], ];
甚至更好,您可以创建一个简短名称来保持您的 policy
数组整洁!
return [ 'policy' => [ 'active', // your new rule ! 'browser', // if 2FA is not activated for the account, will check anyways if the browser is known ], [...] 'mapping' => [ [...] 'active' => \Auth\Policies\ActivePolicy::class, ], ];
一些策略需要在用户使用 2FA 成功登录时执行操作(例如:写入 cookie 或在数据库中写入某些内容)。您可以在策略的 onSucceed()
方法中定义您的回调
/** * An action to perform on successful 2FA login. * May be used to remember stuff for the next policy check. * * @return void */ public function onSucceed(): void { Cookie::queue( '2fa_remember', $this->attempt->uid, 1440 ); }
自定义驱动器
如果您在整个过程中需要更多的灵活性,您可以扩展 BaseDriver
类并通过覆盖任何方法来更改其工作流程。
namespace App\Auth\Drivers; use Airondev\Laravel2FA\Drivers\BaseDriver; use Airondev\Laravel2FA\Contracts\TwoFactorAuthenticatableContract as Authenticatable; class CustomDriver extends BaseDriver { /** * Check if must trigger 2FA token for this user. * * @param \Illuminate\Http\Request $request * @param \Airondev\Laravel2FA\Contracts\TwoFactorAuthenticatableContract $user * * @return bool */ public function mustTrigger(Request $request, Authenticatable $user): bool { // custom workflow. } }
不要忘记在配置文件中更新 driver
键
return [ 'driver' => \App\Auth\Drivers\CustomDriver::class; ];
⚠️ 如果您希望从头开始构建驱动器,您必须实现 TwoFactorDriverContract。
贡献
请随意为此包做出贡献!
如果您发现任何安全问题,请通过 thomas@Airondev.agency 联系我,而不是创建公开的 GitHub 问题。
致谢
许可证
MIT 许可证(MIT)。有关更多信息,请参阅 许可证文件。