Filament 附带的默认登录类在大多数情况下就足够了,因为它包含电子邮件和密码字段以及remember_me复选框。
但是,在某些情况下,您必须覆盖默认行为并相应地实现功能。因此,在本文中,我们将讨论如何覆盖默认登录类并在其上实现我们自己的功能。
Configuration 配置
在处理 Custom Login Class 之前,我们首先需要了解 FilamentPhp 如何在后台处理登录流程。要了解这一点,我们首先要研究一下 FilamentPHP 附带的默认 Service Provider,即位于 app/Providers/Filament/ 命名空间中的 AdminPanelProvider。
如果我们查看该类,则有一个链接到 $panel 的 login 方法,它指示应该为此面板启用 login 功能。
如果我们继续研究该方法的实现,我们将看到如下内容:
/**
* @param string | Closure | array<class-string, string> | null $action
*/
public function login(string | Closure | array | null $action = Login::class): static
{
$this->loginRouteAction = $action;
return $this;
}
因此,默认情况下,如果我们不将任何类传递给此 login() 方法,则使用默认的 Login::class。
所以,这里的一般思路是扩展这个类,根据我们的需要对这个类进行必要的更改,并将该类传递给 login() 方法。
定义自定义 Login 类
因此,让我们首先通过扩展默认登录类来定义自定义登录类。我们将在 app/Filament/Pages 命名空间中定义它并将其命名为 CustomLogin。
CustomLogin::class 目前如下所示:
<?php
namespace App\Filament\Pages;
use Filament\Http\Livewire\Auth\Login;
class CustomLogin extends Login
{
//
}
默认的 Login 类包括与 login 相关的所有内容,例如
static view 属性(如果我们想传递自己的 view,可以覆盖它)
authenticate 方法(如果我们想更新用户的身份验证方式,我们可以覆盖它)
getTitle 和 getHeading 方法覆盖页面的标题和标题
以及其他类似的属性和方法,这些属性和方法根据我们的需要被覆盖。
使用 Username 而不是 Email 进行身份验证
例如,我们将覆盖默认行为,并使用用户名而不是默认电子邮件进行身份验证。
有多种方法可以做到这一点,我们可以覆盖 getForms 方法并传递一个 $this->getUsernameFormComponent() 方法而不是 $this->getEmailFormComponent() ,
在 getUsernameFormComponent() 方法上,我们可以为 username 字段传递一个表单组件。
但是,我们将保持简单,只需覆盖 getEmailFormComponent() 方法并为 username 字段传递一个表单组件。
当我们为 Username 字段传递 Form 组件时,getEmailFormComponent() 看起来像这样
protected function getEmailFormComponent(): Component
{
return TextInput::make('username')
->label('Username')
->required()
->autofocus()
->extraInputAttributes(['tabindex' => 1])
->autocomplete();
}
我们还需要覆盖 getCredentialsFromFormData 方法,因为此方法已传递给 authenticate 方法,并将 email key 替换为 username key。
更改后,getCredentialsFromFormData 如下所示:
protected function getCredentialsFromFormData(array $data): array
{
return [
'username' => $data['username'],
'password' => $data['password'],
];
}
经过必要的修改后,最终的 login 类如下所示:
<?php
namespace App\Filament\Pages;
use Filament\Facades\Filament;
use Filament\Pages\Auth\Login;
use Filament\Forms\Components\Component;
use Filament\Forms\Components\TextInput;
use Illuminate\Contracts\Support\Htmlable;
class CustomLogin extends Login
{
public function mount(): void
{
if (Filament::auth()->check()) {
redirect()->intended(Filament::getUrl());
}
if (app()->environment('local')) {
$this->form->fill([
'username' => 'admin',
'password' => 'password',
]);
}
}
protected function getCredentialsFromFormData(array $data): array
{
return [
'username' => $data['username'],
'password' => $data['password'],
];
}
public function getTitle(): string|Htmlable
{
return __('Admin Login');
}
public function getHeading(): string|Htmlable
{
return __('Admin Login');
}
protected function getEmailFormComponent(): Component
{
return TextInput::make('username')
->label('Username')
->required()
->autofocus()
->extraInputAttributes(['tabindex' => 1])
->autocomplete();
}
}
除了上面讨论的方法外,我还重写了其他一些方法,比如 getTitle、getHeading 和 mount 方法。mount 方法有点有趣,因为它检查用户是否通过身份验证,如果是,则它将重定向到预期的仪表板。
如果应用程序未登录,则如果应用程序的环境是本地的,我们将使用默认的用户名和密码填写表单。