Filament 中的用户默认情况下可以使用他们的电子邮件地址和密码登录. 然而, 您可以启用多重身份验证 (MFA) 为您的用户帐户增加一层额外的安全保障.
当 MFA 启用时,用户必须执行一个额外步骤,才能通过身份验证并访问应用程序。
Filament 包含两种你可以开箱即用地启用的 MFA 方法:
在 Filament 中,用户从其个人资料页面设置多重身份验证。如果您使用 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',
];
/**
* @return array<string, string>
*/
protected function casts(): array
{
return [
// ...
'app_authentication_secret' => 'encrypted',
];
}
// ...
}接下来,你需要在 User 模型上实现 HasAppAuthentication 接口。这为 Filament 提供了必要的方法,用于与秘密代码和有关集成的其他信息进行交互:
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;
}
}由于 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 表添加一个新列 (或为此面板中用于你的 "可认证的" 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',
];
/**
* @return array<string, string>
*/
protected function casts(): array
{
return [
// ...
'app_authentication_recovery_codes' => 'encrypted:array',
];
}
// ...
}接下来,你应该在 User 模型上实现 HasAppAuthenticationRecovery 接口. 这为 Filament 提供了与恢复码交互的必要方法:
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();
}
}由于 Filament 在您的 User 模型上使用接口,而不是假设 app_authentication_recovery_codes 列存在,因此您可以使用任何您想要的列名。如果您想将恢复码存储在不同的表中,甚至可以使用完全不同的模型。
最后,您应该在您的面板中启用应用程序身份验证恢复码功能。 为此,将 recoverable() 方法传递给 AppAuthentication 实例 在 multiFactorAuthentication() 方法中 在 配置 中:
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),
]);
}默认情况下,用户可以访问其个人资料以重新生成其恢复代码。如果您想阻止此操作,您可以使用 regenerableRecoveryCodes(false) 方法在 AppAuthentication 实例上在 multiFactorAuthentication() 方法中在配置中:
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),
]);
}每个应用认证集成都有一个“品牌名称”,在认证应用中显示。默认情况下,这是您的应用的名称。如果您想更改此名称,您可以在 配置 中的 multiFactorAuthentication() 方法中的 AppAuthentication 实例上使用 brandName() 方法:
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
AppAuthentication::make()
->brandName('Filament Demo'),
]);
}电子邮件认证会向用户发送一次性代码到他们的电子邮件地址,他们必须输入这些代码以验证他们的身份。
要在面板中启用电子邮件验证,您必须首先在您的users 表(或者用于此面板中“可验证”Eloquent 模型的任何表)中添加一个新列。该列需要存储一个布尔值,指示电子邮件验证是否已启用:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->boolean('has_email_authentication')->default(false);
});在 User 模型中, 你需要确保此列被转换为布尔类型:
use Filament\Models\Contracts\FilamentUser;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements FilamentUser, MustVerifyEmail
{
/**
* @return array<string, string>
*/
protected function casts(): array
{
return [
// ...
'has_email_authentication' => 'boolean',
];
}
// ...
}接下来,你应该实现 HasEmailAuthentication 接口在 User 模型上。这为 Filament 提供了必要的方法,以与指示电子邮件身份验证是否启用的列进行交互:
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();
}
}由于 Filament 在您的 User 模型上使用接口,而不是假设 has_email_authentication 列存在,您可以使用任何您想要的列名。您甚至可以使用完全不同的模型,如果您想将设置存储在不同的表中。
最后,您应该在您的面板中激活电子邮件认证功能。为此,请使用 配置 中的 multiFactorAuthentication() 方法,并向其传递一个 EmailAuthentication 实例:
use Filament\Auth\MultiFactor\Email\EmailAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
EmailAuthentication::make(),
]);
}邮箱验证码的有效期为4分钟,之后便会失效。
要更改过期时间,例如,使生成的验证码在生成后仅在2分钟内有效,你可以在 EmailAuthentication 实例上使用 codeExpiryMinutes() 方法,并将其设置为 2:
use Filament\Auth\MultiFactor\Email\EmailAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
EmailAuthentication::make()
->codeExpiryMinutes(2),
]);
}默认情况下,用户无需设置多重身份验证。您可以通过将 isRequired: true 作为参数传递给 configuration 中的 multiFactorAuthentication() 方法来要求用户进行配置:
use Filament\Auth\MultiFactor\App\AppAuthentication;
use Filament\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->multiFactorAuthentication([
AppAuthentication::make(),
], isRequired: true);
}当此功能启用时,如果用户尚未设置,他们登录后将被提示设置多重身份验证。
在 Filament 中,多因素认证过程发生于用户实际登录到应用程序之前。这让您可以确保,任何用户都无法在未通过多因素认证步骤的情况下登录并访问应用程序。您无需记住将中间件添加到任何已认证路由中,以确保用户已完成多因素认证步骤。
然而,如果您的 Laravel 应用中还有其他部分对用户进行身份验证,请记住,如果他们已经在其他地方进行了身份验证然后访问面板,他们将不会被要求进行多因子认证,除非 多因子认证是必需的 且他们尚未设置。