用户
多因素认证
介绍
Filament 用户默认可以使用邮箱和密码登录。不过,你可以启用多因素认证(MFA),为用户提供额外的安全保障。
启用MFA后,用户在通过身份验证并访问应用之前必须执行额外的验证。
Filament 包括两种可以开箱即用的 MFA 方法:
- 应用身份验证使用与 Google 身份验证器兼容的应用(如 Google 身份验证器、Authy 或 Microsoft 身份验证器应用)生成用于验证用户的基于时间的一次性密码(TOTP)。
- 电子邮件身份验证向用户的电子邮件地址发送一个一次性代码,用户必须输入该代码以验证其身份。
在 Filament 中,用户在他们的个人资料(profile)页面设置多因素身份验证。如果你使用 Filament 的个人资料页面功能,设置多因素身份验证将自动将对应的 UI 元素添加到个人资料页面:
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->profile();
}
应用身份验证
要在面板中启用应用身份验证,你必须首先向 users
表(或此面板中用于“可身份验证” 的 Eloquent 模型的任何表)添加一个新字段。该字段需要存储用于生成和验证基于时间的一次性密码的密钥。它可以是迁移中的普通 text()
字段:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->text('app_authentication_secret')->nullable();
});
在 User
模型中,你需要确保该字段是加密的且 $hidden
,因这是十分敏感的信息,应该保证存储安全:
use Filament\Models\Contracts\FilamentUser;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements FilamentUser, MustVerifyEmail
{
// ...
/**
* @var array<string>
*/
protected $hidden = [
// ...
'app_authentication_secret',
];
/**
* @var array<string, string>
*/
protected $casts = [
// ...
'app_authentication_secret' => 'encrypted',
];
// ...
}
然后,你需要在 User
模型中实现 HasAppAuthentication
接口。该接口提供了与密钥及其他集成信息进行交互的必要方法:
use Filament\Auth\MultiFactor\App\Contracts\HasAppAuthentication;
use Filament\Models\Contracts\FilamentUser;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements FilamentUser, HasAppAuthentication, MustVerifyEmail
{
// ...
public function getAppAuthenticationSecret(): ?string
{
// This method should return the user's saved app authentication secret.
return $this->app_authentication_secret;
}
public function saveAppAuthenticationSecret(?string $secret): void
{
// This method should save the user's app authentication secret.
$this->app_authentication_secret = $secret;
$this->save();
}
public function getAppAuthenticationHolderName(): string
{
// In a user's authentication app, each account can be represented by a "holder name".
// If the user has multiple accounts in your app, it might be a good idea to use
// their email address as then they are still uniquely identifiable.
return $this->email;
}
}
TIP
由于 Filament 在 User
模型上实现了接口,而非假定 app_authentication_secret
字段存在,你可以使用任何想要使用的字段名。如果你的 密钥存储在不同的表格种,你甚至可以使用完全不同的模型。
最后,你应该在面板中激活应用身份认证功能。为此,请在配置中使用 multiFactorAuthentication()
方法,并传入一个 AppAuthentication
实例:
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
AppAuthentication::make(),
]);
}
设置应用恢复码
如果用户丢失访问他们的双因素身份验证应用的权限,他们将无法登录到应用中。为了防止这种情况,你可以生成一组恢复码,用户可以在失去对双因素身份验证应用的访问权限时使用这些代码登录。
与 app_authentication_secret
字段类似, 你应该向 users
表(或面板中使用 “authenticatable” Eloquent 模型的任何表)添加一个新字段。该字段用于存储恢复码。它可以是迁移中的普通 text()
字段:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->text('app_authentication_recovery_codes')->nullable();
});
在 User
模型中,你需要该字段加密成数组且为 $hidden
,因为它是敏感信息,应该保证存储安全:
use Filament\Auth\MultiFactor\App\Contracts\HasAppAuthentication;
use Filament\Models\Contracts\FilamentUser;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements FilamentUser, HasAppAuthentication, MustVerifyEmail
{
// ...
/**
* @var array<string>
*/
protected $hidden = [
// ...
'app_authentication_recovery_codes',
];
/**
* @var array<string, string>
*/
protected $casts = [
// ...
'app_authentication_recovery_codes' => 'encrypted:array',
];
// ...
}
接下来,你需要在 User
模型中实现 HasAppAuthenticationRecovery
接口。该接口提供了与恢复码进行交互的必要方法:
use Filament\Auth\MultiFactor\App\Contracts\HasAppAuthentication;
use Filament\Auth\MultiFactor\App\Contracts\HasAppAuthenticationRecovery;
use Filament\Models\Contracts\FilamentUser;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements FilamentUser, HasAppAuthentication, HasAppAuthenticationRecovery, MustVerifyEmail
{
// ...
/**
* @return ?array<string>
*/
public function getAppAuthenticationRecoveryCodes(): ?array
{
// This method should return the user's saved app authentication recovery codes.
return $this->app_authentication_recovery_codes;
}
/**
* @param array<string> | null $codes
*/
public function saveAppAuthenticationRecoveryCodes(?array $codes): void
{
// This method should save the user's app authentication recovery codes.
$this->app_authentication_recovery_codes = $codes;
$this->save();
}
}
TIP
由于 Filament 在 User
模型上使用了接口,而不是假定存在 app_authentication_recovery_codes
字段,因此你可以使用任何你想要的字段名。如果你的恢复码保存在不同的表格中,你甚至可以使用完全不同的模型。
最后,你应该在面板中激活应用身份验证恢复代码功能。为此,请在配置中的 multiFactorAuthentication()
方法中
将 recovery()
方法传递给 AppAuthentication
实例:
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
AppAuthentication::make()
->recoverable(),
]);
}
修改恢复码生成的数量
默认情况下,Filament 为每位用户生成 8 个恢复码。如果你想修改,可以在配置的 multiFactorAuthentication()
方法中,使用 AppAuthentication
实例调用 recoveryCodeCount()
方法:
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
AppAuthentication::make()
->recoverable()
->recoveryCodeCount(10),
]);
}
防止用户重新生成恢复码
默认情况下,用户可以访问它们的个人资料页来重新生成恢复码。如果你想要阻止重新生成,可以在配置的 multiFactorAuthentication()
方法中,使用 AppAuthentication
实例调用 regenerableRecoveryCodes(false)
方法:
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
AppAuthentication::make()
->recoverable()
->regenerableRecoveryCodes(false),
]);
}
修改应用码到期时间
应用码是使用基于时间的一次性密码(TOTP)算法发布的,这意味着它们在生成前后仅在短时间内有效。该时间是在时间“窗口”中定义的。默认情况下, Filament 使用 8
的过期窗口,即在生成时间的两侧创建 4 分钟的有效期(总共 8 分钟)。
要更改窗口,例如使其在生成后仅在 2 分钟内有效,你可以在 AppAuthentication
实例上使用 codeWindow()
方法,将其设置为 4
:
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
AppAuthentication::make()
->codeWindow(4),
]);
}
Customizing the app authentication brand name
Each app authentication integration has a “brand name” that is displayed in the authentication app. By default, this is the name of your app. If you want to change this, you can use the brandName()
method on the AppAuthentication
instance in the multiFactorAuthentication()
method in the configuration:
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
AppAuthentication::make()
->brandName('Filament Demo'),
]);
}
Email 身份认证
Email authentication sends the user one-time codes to their email address, which they must enter to verify their identity.
To enable email authentication in a panel, you must first add a new column to your users
table (or whichever table is being used for your “authenticatable” Eloquent model in this panel). The column needs to store a boolean indicating whether or not email authentication is enabled:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->boolean('has_email_authentication')->default(false);
});
In the User
model, you need to ensure that this column is cast to a boolean:
use Filament\Models\Contracts\FilamentUser;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements FilamentUser, MustVerifyEmail
{
// ...
/**
* @var array<string, string>
*/
protected $casts = [
// ...
'has_email_authentication' => 'boolean',
];
// ...
}
Next, you should implement the HasEmailAuthentication
interface on the User
model. This provides Filament with the necessary methods to interact with the column that indicates whether or not email authentication is enabled:
use Filament\Auth\MultiFactor\Email\Contracts\HasEmailAuthentication;
use Filament\Models\Contracts\FilamentUser;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements FilamentUser, HasEmailAuthentication, MustVerifyEmail
{
// ...
public function hasEmailAuthentication(): bool
{
// This method should return true if the user has enabled email authentication.
return $this->has_email_authentication;
}
public function toggleEmailAuthentication(bool $condition): void
{
// This method should save whether or not the user has enabled email authentication.
$this->has_email_authentication = $condition;
$this->save();
}
}
TIP
Since Filament uses an interface on your User
model instead of assuming that the has_email_authentication
column exists, you can use any column name you want. You could even use a different model entirely if you want to store the setting in a different table.
Finally, you should activate the email authentication feature in your panel. To do this, use the multiFactorAuthentication()
method in the configuration, and pass an EmailAuthentication
instance to it:
use Filament\Auth\MultiFactor\Email\EmailAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
EmailAuthentication::make(),
]);
}
Changing the email code expiration time
Email codes are issued with an lifetime of 4 minutes, after which they expire.
To change the expiration period, for example to only be valid for 2 minutes after codes are generated, you can use the codeExpiryMinutes()
method on the EmailAuthentication
instance, set to 2
:
use Filament\Auth\MultiFactor\Email\EmailAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
EmailAuthentication::make()
->codeExpiryMinutes(2),
]);
}
Requiring multi-factor authentication
By default, users are not required to set up multi-factor authentication. You can require users to configure it by passing isRequired: true
as a parameter to the multiFactorAuthentication()
method in the configuration:
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
AppAuthentication::make(),
], isRequired: true);
}
When this is enabled, users will be prompted to set up multi-factor authentication after they sign in, if they have not already done so.
Security notes about multi-factor authentication
In Filament, the multi-factor authentication process occurs before the user is actually authenticated into the app. This allows you to be sure that no users can authenticate and access the app without passing the multi-factor authentication step. You do not need to remember to add middleware to any of your authenticated routes to ensure that users completed the multi-factor authentication step.
However, if you have other parts of your Laravel app that authenticate users, please bear in mind that they will not be challenged for multi-factor authentication if they are already authenticated elsewhere and then visit the panel, unless multi-factor authentication is required and they have not set it up yet.
Edit on GitHubStill need help? Join our Discord community or open a GitHub discussion