Laravel Filament 3 修改登录认证字段,比如使用username 而不是默认的 email 字段登录的方法

165 阅读2分钟

Filament 默认登录页面是使用 email 和 password 两个字段校验用户身份的,但是有的时候我们可能需要修改登录字段,比如使用 username 和 password 的组合,而不是 email 字段。在 Filament 3 中实现这一需求十分简单,通过自定义身份验证功能自定义一个登录类并重写相关方法即可 目录

创建自定义登录类

让我们创建自己的登录页面,并将其注入登录方法中。我将在 App\Filament\Auth 目录中创建这个类。它需要扩展 Filament 中的默认 Login 类。

use Filament\Pages\Auth\Login as BaseLogin;
class Login extends BaseLogin { // ... }

Filament默认的 Login 类的完整代码参考 github。为了实现上文中的需求,我们需要重写三个方法:

  • form() – 以不同方式显示表单
  • getCredentialsFromFormData() – 正确处理表单数据
  • throwFailureValidationException() – 正确显示错误

此外,我们将用自己的新方法 getUsernameFormComponent() 替换 getEmailFormComponent() 方法,以使用 username 字段代替 email 字段,我们将把该字段称为 “用户名”。

自定义 getUsernameFormComponent 方法

protected function getUsernameFormComponent(): Component
{
    return TextInput::make('username') 
    ->label('用户名')
    ->required()
    ->autocomplete() 
    ->autofocus() 
    ->extraInputAttributes(['tabindex' => 1]); 
}

上述代码中,我们自定义了一个getUsernameFormComponent()方法,包含一个TextInput类型的表单字段。

重写 form 方法

public function form(Form $form): Form {
    return $form ->schema([ //$this->getEmailFormComponent(),
    $this->getUsernameFormComponent(), 
    $this->getPasswordFormComponent(),
    $this->getRememberFormComponent(), ]) 
    ->statePath('data');
}

通过覆盖 form 方法,使用 getUsernameFormComponent() 替换默认的 $this->getEmailFormComponent(),这样就实现了使用 username 字段替换 email 字段。

重写 getCredentialsFromFormData() 方法

接下来我们要重写 getCredentialsFromFormData() 方法,使用 username 进行身份验证。

protected function getCredentialsFromFormData(array $data): array {
    return [ 'username' => $data['username'], 'password' => $data['password'], ]; 
}

重写 throwFailureValidationException() 方法

现在的问题是验证错误仍然发生在 data.email 字段,而不是 data.username 字段,这意味着错误信息将不可见。我们需要通过覆盖throwFailureValidationException()方法来解决这个问题:

protected function throwFailureValidationException(): never {
    throw ValidationException::withMessages([
    'data.username' => __('filament-panels::pages/auth/login.messages.failed'), 
    ]);
}

完整的自定义 login 类代码

经过上面的步骤,我们已经按照需求完成了自定义 login 类的所有代码编写,完整代码如下:

<?php namespace App\Filament\Auth; use Filament\Forms\Form; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Component; use Filament\Pages\Auth\Login as BaseLogin; use Illuminate\Validation\ValidationException; class Login extends BaseLogin { public function form(Form $form): Form { return $form ->schema([ //$this->getEmailFormComponent(), $this->getUsernameFormComponent(), $this->getPasswordFormComponent(), $this->getRememberFormComponent(), ]) ->statePath('data'); } protected function getUsernameFormComponent(): Component { return TextInput::make('username') ->label('用户名') ->required() ->autocomplete() ->autofocus() ->extraInputAttributes(['tabindex' => 1]); } protected function getCredentialsFromFormData(array $data): array { return [ 'username' => $data['username'], 'password' => $data['password'], ]; } protected function throwFailureValidationException(): never { throw ValidationException::withMessages([ 'data.username' => __('filament-panels::pages/auth/login.messages.failed'), ]); } }

应用自定义 login 类

最后,我们要修改 app/Providers/Filament/AdminPanelProvider.php 文件,在 login 中调用自定义的 login 类即可。

use App\Filament\Auth\Login; class AdminPanelProvider extends PanelProvider { public function panel(Panel $panel): Panel { return $panel ->default() ->id('admin') ->path('admin') ->login(Login::class) // ... } }