darkghosthunter/laraguard

该包已弃用,不再维护。作者建议使用laragear/two-factor包。

为所有用户提供即插即用的本地2FA身份验证

v4.0.3 2022-02-16 18:30 UTC

README

请迁移到新包。

Laraguard

为所有用户提供即插即用的基于TOTP的二次身份验证。

此包允许使用6位数字代码进行身份验证。无需外部API。

要求

对于旧版本的支持,请考虑赞助或捐赠以帮助。

安装

启动Composer并在您的项目中要求此包。

composer require darkghosthunter/laraguard

就这样。

这是如何工作的

此包添加了一个Contract来检测在凭证被认为是有效之后,是否应该使用二次身份验证作为第二层身份验证。

它包含一个自定义的view和一个callback来处理登录尝试期间的二次身份验证。

无需中间件或新守卫即可工作,但您可以选择完全手动进行。

用法

首先,通过发布迁移并进行迁移来创建two_factor_authentications

php artisan vendor:publish --provider="DarkGhostHunter\Laraguard\LaraguardServiceProvider" --tag="migrations"
php artisan migrate

这将为您想要附加到2FA的每个模型创建一个处理二次身份验证信息的表。

如果您是从3.0版本升级,则应运行一个特殊的迁移。

TwoFactorAuthenticatable contractTwoFactorAuthentication trait添加到User模型中,或任何其他您想要提供二次身份验证的模型。

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use DarkGhostHunter\Laraguard\TwoFactorAuthentication;
use DarkGhostHunter\Laraguard\Contracts\TwoFactorAuthenticatable;

class User extends Authenticatable implements TwoFactorAuthenticatable
{
    use TwoFactorAuthentication;
    
    // ...
}

合同用于标识使用二次身份验证的模型,而特性方便地实现了处理它所需的方法。

启用二次身份验证

为了成功启用二次身份验证,用户必须在其身份验证器应用和应用程序之间同步共享密钥。

一些免费的身份验证器应用包括iOS身份验证器FreeOTPAuthyandOTPGoogle 身份验证器Microsoft身份验证器等。

开始时,使用createTwoFactorAuth()方法生成所需的数据。完成后,您可以在视图中将共享密钥显示给用户,作为字符串或SVG编码的QR码。

use Illuminate\Http\Request;

public function prepareTwoFactor(Request $request)
{
    $secret = $request->user()->createTwoFactorAuth();
    
    return view('user.2fa', [
        'as_qr_code' => $secret->toQr(),     // As QR Code
        'as_uri'     => $secret->toUri(),    // As "otpauth://" URI.
        'as_string'  => $secret->toString(), // As a string
    ]);
}

当您对一个已经启用了双因素认证的用户使用 createTwoFactorAuth() 时,之前的数据将永久无效。这确保用户在任何时候都不会同时启用两个共享密钥。

然后,用户必须使用他们的认证器应用生成的代码确认共享密钥。如果代码有效,confirmTwoFactorAuth() 方法将自动启用它。

use Illuminate\Http\Request;

public function confirmTwoFactor(Request $request)
{
    $request->validate([
        'code' => 'required|numeric'
    ]);
    
    $activated = $request->user()->confirmTwoFactorAuth($request->code);
    
    // ...
}

如果用户没有输入正确的代码,方法将返回 false。您可以告诉用户检查其设备的时区,或者使用 createTwoFactorAuth() 创建另一个共享密钥。

恢复代码

每次启用双因素认证时,都会自动生成恢复代码。默认情况下,会创建一个包含十个8字符一次性代码的集合。

您可以使用 getRecoveryCodes() 显示它们。

use Illuminate\Http\Request;

public function confirmTwoFactor(Request $request)
{
    if ($request->user()->confirmTwoFactorAuth($request->code)) {
        return $request->user()->getRecoveryCodes();
    } else {
        return 'Try again!';
    }
}

您可以自由决定如何向用户展示这些代码,但请确保在成功启用双因素认证后立即展示一次,并要求他们将其打印下来。

当用户发送的是恢复代码而不是TOTP代码时,这些恢复代码会自动处理。如果是恢复代码,包将使用并标记它为无效。

用户可以使用 generateRecoveryCodes() 生成一批新的代码,这将自动使之前的批次无效。

use Illuminate\Http\Request;

public function showRecoveryCodes(Request $request)
{
    return $request->user()->generateRecoveryCodes();
}

如果用户在没有禁用双因素认证的情况下耗尽了他的恢复代码,或者恢复代码被停用,他可能永远无法使用认证器应用解锁。确保在这些情况下有应对措施。

登录

要登录,用户必须输入TOTP代码以及他们的凭据。只需使用Laraguard的 attemptWhen(),它会自动为您进行验证。默认情况下,它检查 2fa_code 输入名称,但您可以指定自己的。

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use DarkGhostHunter\Laraguard\Laraguard;

public function login(Request $request)
{
    // ...
    
    $credentials = $request->only('email', 'password');
    
    if (Auth::attemptWhen($credentials, Laraguard::hasCode(), $request->filled('remember'))) {
        return redirect()->home(); 
    }
    
    return back()->withErrors(['email' => 'Bad credentials'])
}

在幕后,一旦用户从您选择的守卫中检索并验证,它将进行额外的检查以验证有效的TOTP代码。如果它无效,它将返回false并且不会发生认证。

对于Laravel Breeze,您可能需要编辑 LoginRequest::authenticate() 调用。对于Laravel Fortify和Jetstream,您可能需要使用 Fortify::authenticateUsing() 方法设置自定义回调。

分离TOTP要求

在某些情况下,您可能希望告诉用户认证失败不是因为凭据错误,而是因为TOTP代码无效。

您可以使用执行相同操作的 hasCodeOrFails() 方法,但会抛出一个验证异常,框架会优雅地处理它。它甚至可以接受一个自定义的失败消息,否则将使用默认的 翻译 行。

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use DarkGhostHunter\Laraguard\Laraguard;

public function login(Request $request)
{
    // ...
    
    $credentials = $request->only('email', 'password');
    
    if (Auth::attemptWhen($credentials, Laraguard::hasCodeOrFails(), $request->filled('remember'))) {
        return redirect()->home(); 
    }
    
    return back()->withErrors(['email', 'Authentication failed!']);
}

由于它是 ValidationException,因此您可以捕获它并进行更复杂的事情,比如那些等待用户输入正确TOTP代码的登录过程视图。

停用

您可以使用 disableTwoFactorAuth() 方法停用特定用户的双因素认证。这将自动使认证数据无效,使用户可以仅凭凭据登录。

public function disableTwoFactorAuth(Request $request)
{
    $request->user()->disableTwoFactorAuth();
    
    return 'Two-Factor Authentication has been disabled!';
}

事件

除了默认的认证事件之外,还会触发以下事件。

  • TwoFactorEnabled:用户已启用双因素认证。
  • TwoFactorRecoveryCodesDepleted:用户已使用他的最后一个恢复代码。
  • TwoFactorRecoveryCodesGenerated:用户已生成一组新的恢复代码。
  • TwoFactorDisabled:用户已禁用双因素认证。

您可以使用 TwoFactorRecoveryCodesDepleted 来提示用户创建更多恢复代码或将更多代码通过邮件发送给他们。

中间件

Laraguard 包含两个用于您路由的中间件:2fa.enabled2fa.confirm

为了避免出现意外结果,中间件仅对实现 TwoFactorAuthenticatable 接口的用户模型进行操作。如果用户模型没有实现该接口,中间件将绕过任何双因素认证逻辑。

强制要求双因素认证

如果您需要在用户进入特定路由之前确保已启用双因素认证,可以使用 2fa.enabled 中间件。实现了 TwoFactorAuthenticatable 接口但未启用双因素认证的用户将被重定向到包含警告的路由,默认为 2fa.notice

Route::get('system/settings')
    ->uses('SystemSettingsController@show')
    ->middleware('2fa.enabled');

您可以使用本包中包含的视图轻松实现,可选地添加一个指向启用双因素认证的 URL。

use Illuminate\Support\Facades\Route;

Route::view('2fa-required', 'laraguard::notice', [
    'url' => url('settings/2fa')
])->name('2fa.notice');

或者,您可以直接将用户重定向到可以启用双因素认证的命名路由。

use Illuminate\Support\Facades\Route

Route::get('system/settings')
    ->uses('SystemSettingsController@show')
    ->middleware('2fa.enabled:settings.2fa');

确认双因素认证

password.confirm 中间件 类似,如果您已启用双因素认证,您也可以使用 2fa.confirm 要求用户确认操作。

Route::get('api/token')
    ->uses('ApiTokenController@show')
    ->middleware('2fa.confirm');

由于未启用双因素认证的用户不会要求输入代码,您可以使用 2fa.require 来强制要求。

Route::get('api/token')
    ->uses('ApiTokenController@show')
    ->middleware('2fa.require', '2fa.confirm');

Laraguard 使用其 Confirm2FACodeController 来处理表单视图。您可以指定自己的控制器操作Confirms2FACode 特性将帮助您避免重复造轮子。

验证

有时您可能想在应用程序的任何部分手动触发已认证用户的 TOTP 验证。您可以使用 totp_code 规则对已认证用户进行 TOTP 代码验证。

public function checkTotp(Request $request)
{
    $request->validate([
        'code' => 'required|totp_code'
    ]);

    // ...
}

如果用户已认证、已启用双因素认证并且代码正确,则此规则将成功。

翻译

Laraguard 包含翻译文件(仅英文),您可以直接在应用程序中使用这些文件。这些文件还用于验证规则

public function disableTwoFactorAuth()
{
    // ...

    session()->flash('2fa_disabled', trans('laraguard::messages.disabled'));

    return back();
}

要添加您自己的语言,发布翻译文件。这些文件将位于 resources/vendor/laraguard

php artisan vendor:publish --provider="DarkGhostHunter\Laraguard\LaraguardServiceProvider" --tag="translations"

配置

要进一步配置包,发布配置文件和资源

php artisan vendor:publish --provider="DarkGhostHunter\Laraguard\LaraguardServiceProvider"

您将收到包含以下内容的 config/laraguard.php 配置文件

return [
    'model' => \DarkGhostHunter\Laraguard\Eloquent\TwoFactorAuthentication::class,
    'cache' => [
        'store' => null,
        'prefix' => '2fa.code'
    ],
    'recovery' => [
        'enabled' => true,
        'codes' => 10,
        'length' => 8,
	],
    'safe_devices' => [
        'enabled' => false,
        'max_devices' => 3,
        'expiration_days' => 14,
	],
    'confirm' => [
        'timeout' => 10800,
        'view' => 'DarkGhostHunter\Laraguard\Http\Controllers\Confirm2FACodeController@showConfirmForm',
        'action' => 'DarkGhostHunter\Laraguard\Http\Controllers\Confirm2FACodeController@confirm'
    ],
    'secret_length' => 20,
    'issuer' => env('OTP_TOTP_ISSUER'),
    'totp' => [
        'digits' => 6,
        'seconds' => 30,
        'window' => 1,
        'algorithm' => 'sha1',
    ],
    'qr_code' => [
        'size' => 400,
        'margin' => 4
    ],
];

Eloquent 模型

return [
    'model' => \DarkGhostHunter\Laraguard\Eloquent\TwoFactorAuthentication::class,
];

这是保存双因素认证数据(如共享密钥和恢复代码)并关联到实现 TwoFactorAuthenticatable 接口的模型的模型。

如果您愿意,可以更改此模型,只要它实现 TwoFactorTotp 接口即可。

缓存存储

return  [
    'cache' => [
        'store' => null,
        'prefix' => '2fa.code'
    ],
];

RFC 6238 指出,一次性密码不应该能够重复使用,即使它仍然在时间窗口内。为此,我们需要使用缓存来保存给定期限内的代码。

您可以更改要使用的存储方式,这是应用程序默认使用的存储方式,以及用作缓存键的指定前缀,以防发生冲突。

恢复

return [
    'recovery' => [
        'enabled' => true,
        'codes' => 10,
        'length' => 8,
    ],
];

恢复代码处理默认启用,但您可以选择禁用它。如果这样做,请确保用户可以通过其他方式验证,例如发送包含指向登录并禁用双因素认证的签名字符串的链接的电子邮件,或者发送短信。

生成代码的数量和长度是可配置的。对于大多数认证场景,10个8位随机字符的代码就足够了。

安全设备

return [
    'safe_devices' => [
        'enabled' => false,
        'max_devices' => 3,
        'expiration_days' => 14,
    ],
];

启用此选项将允许应用程序通过cookie“记住”一个设备,允许它在验证该设备中的代码后绕过双因素认证。当用户再次在该设备上登录时,将不会再次提示输入2FA代码。

可以保存的设备数量有限,但通常三个就足够了(手机、平板电脑和电脑)。新设备将取代已注册的最老设备。设备在设置的天数后不再被视为“安全”。

您可以在注册后更改可保存的最大设备数量和有效天数。更多设备和更长的有效期将使双因素认证的安全性降低。

重新启用双因素认证时,设备列表将自动失效。

确认中间件

return [
    'confirm' => [
        'timeout' => 10800, // 3 hours
        'view' => 'DarkGhostHunter\Laraguard\Http\Controllers\Confirm2FACodeController@showConfirmForm',
        'action' => 'DarkGhostHunter\Laraguard\Http\Controllers\Confirm2FACodeController@confirm'
    ],
];

如果 viewaction 不是 null,则会注册 2fa/notice2fa/confirm 路由来处理 2fa.confirm 中间件 的2FA代码通知和确认。如果您禁用它,您将必须自行注册路由和控制器操作。

此数组设置

  • 要“记住”2FA代码确认的程度。
  • 显示2FA代码表单的操作。
  • 接收2FA代码并验证它的操作。

密钥长度

return [
    'secret_length' => 20,
];

这控制用于创建共享密钥的长度(以字节为单位)。虽然160位的共享密钥足够了,但您可以根据喜好调整密钥长度。

建议使用128位或160位,因为一些认证器应用程序可能对非RFC推荐长度的长度存在问题。

TOTP配置

return [
    'issuer' => env('OTP_TOTP_ISSUER'),
    'totp' => [
        'digits' => 6,
        'seconds' => 30,
        'window' => 1,
        'algorithm' => 'sha1',
    ],
];

这控制TOTP代码生成和验证机制

  • 发行商:TOTP发行商的名称。默认为应用程序名称。
  • TOTP数字:请求TOTP代码的位数。
  • TOTP秒数:代码被视为有效的秒数。
  • TOTP窗口:保持代码有效的额外秒数步长。
  • TOTP算法:处理代码生成的系统支持的算法。

这些配置值始终作为URI参数传递给认证应用程序

otpauth://totp/Laravel:taylor@laravel.com?secret=THISISMYSECRETPLEASEDONOTSHAREIT&issuer=Laravel&label=taylor%40laravel.com&algorithm=SHA1&digits=6&period=30

这些值将打印到应用程序中每个2FA数据记录中。更改将仅适用于新的激活。

如果您计划使用公开可用的认证器应用,请不要编辑这些参数,因为其中一些可能不支持非标准配置,例如更多的数字、不同的秒数间隔或其他算法。

二维码配置

return [
    'qr_code' => [
        'size' => 400,
        'margin' => 4
    ],
];

此功能控制创建二维码时使用的尺寸和边距,二维码将以SVG格式创建。

从3.0版本升级

安全

如果您发现任何安全相关的问题,请通过电子邮件darkghosthunter@gmail.com报告,而不是使用问题跟踪器。

许可

MIT许可(MIT)。请参阅许可文件获取更多信息。

Laravel是Taylor Otwell的商标。版权所有 © 2011-2021 Laravel LLC。