Laravel 中的无密码身份验证

发布时间 作者

Passwordless Authentication in Laravel image

有时我们不希望用户拥有密码。有时我们希望向用户的电子邮件地址发送一个魔术链接,让他们点击以获得访问权限。

在本教程中,我将逐步介绍一个您可以用来自己实现此功能的过程。此工作流程的主要重点是创建一个签名 URL,它允许我们向用户的电子邮件地址发送特定 URL,并且只有该用户才能访问此 URL。

我们首先希望从我们的迁移、模型和模型工厂中删除密码字段。由于不需要此字段,我们希望确保将其删除,因为它默认情况下不是可空列。这是一个相对简单的过程,因此我不会在此部分显示任何代码示例。趁此机会,我们可以删除密码重置表,因为我们没有密码要重置。

路由应该是我们接下来要关注的内容。我们可以将登录路由创建为一个简单的视图路由,因为我们将在此示例中使用 Livewire。让我们看看如何注册此路由

Route::middleware(['guest'])->group(static function (): void {
Route::view('login', 'app.auth.login')->name('login');
});

我们希望将其包装在 guest 中间件中,以强制在用户已登录的情况下重定向。我不会介绍此示例的 UI,但在本教程末尾,有一个指向 GitHub 上的存储库的链接。让我们逐步介绍我们将用于登录表单的 Livewire 组件。

final class LoginForm extends Component
{
public string $email = '';
 
public string $status = '';
 
public function submit(SendLoginLink $action): void
{
$this->validate();
 
$action->handle(
email: $this->email,
);
 
$this->status = 'An email has been sent for you to log in.';
}
 
public function rules(): array
{
return [
'email' => [
'required',
'email',
Rule::exists(
table: 'users',
column: 'email',
),
]
];
}
 
public function render(): View
{
return view('livewire.auth.login-form');
}
}

我们的组件有两个我们想要使用的属性。电子邮件用于捕获表单输入。然后是状态,因此我们不需要依赖于请求会话。我们有一个返回验证规则的方法。这是我在 Livewire 组件中使用验证规则的首选方法。我们的提交方法是此组件的主要方法,它是我在处理表单组件时使用的命名约定。这对我来说很有意义,但您可以随意选择适合您的命名方法。我们使用 Laravels 容器将一个操作类注入到此方法中,以共享用于创建和发送签名 URL 的逻辑。我们这里要做的就是将输入的电子邮件传递给操作,并设置一个状态以提醒用户正在发送电子邮件。

现在让我们逐步介绍我们要使用的操作。

final class SendLoginLink
{
public function handle(string $email): void
{
Mail::to(
users: $email,
)->send(
mailable: new LoginLink(
url: URL::temporarySignedRoute(
name: 'login:store',
parameters: [
'email' => $email,
],
expiration: 3600,
),
)
);
}
}

此操作只需要发送一封电子邮件。如果需要,我们可以将其配置为排队 - 但在处理需要快速处理的操作时,如果我们正在构建 API,最好将其排队。我们有一个名为 LoginLink 的可邮寄类,我们将要使用的 URL 传递给它。我们的 URL 是通过传入我们要为其生成路由的路由名称以及要作为签名一部分使用的参数来创建的。

final class LoginLink extends Mailable
{
use Queueable, SerializesModels;
 
public function __construct(
public readonly string $url,
) {}
 
public function envelope(): Envelope
{
return new Envelope(
subject: 'Your Magic Link is here!',
);
}
 
public function content(): Content
{
return new Content(
markdown: 'emails.auth.login-link',
with: [
'url' => $this->url,
],
);
}
 
public function attachments(): array
{
return [];
}
}

我们的可邮寄类非常简单,与标准可邮寄类差别不大。我们传入一个表示 URL 的字符串。然后,我们希望将其传递到内容中的 markdown 视图中。

<x-mail::message>
# Login Link
 
Use the link below to log into the {{ config('app.name') }} application.
 
<x-mail::button :url="$url">
Login
</x-mail::button>
 
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>

用户将收到此电子邮件并点击链接,将他们带到签名 URL。让我们注册此路由并看看它是什么样。

Route::middleware(['guest'])->group(static function (): void {
Route::view('login', 'app.auth.login')->name('login');
Route::get(
'login/{email}',
LoginController::class,
)->middleware('signed')->name('login:store');
});

我们希望为此路由使用一个控制器,并确保我们添加了 signed 中间件。现在让我们看一下控制器,看看我们如何处理签名 URL。

final class LoginController
{
public function __invoke(Request $request, string $email): RedirectResponse
{
if (! $request->hasValidSignature()) {
abort(Response::HTTP_UNAUTHORIZED);
}
 
/**
* @var User $user
*/
$user = User::query()->where('email', $email)->firstOrFail();
 
Auth::login($user);
 
return new RedirectResponse(
url: route('dashboard:show'),
);
}
}

我们的第一步是确保 URL 具有有效的签名,如果它没有,我们希望抛出一个未授权的响应。一旦我们知道签名有效,我们就可以查询传入的用户并对其进行身份验证。最后,我们返回一个重定向到仪表板的响应。

我们的用户现在已成功登录,我们的旅程已完成。但是,我们还需要看看注册路由。让我们接下来添加此路由。这同样将是一个视图路由。

Route::middleware(['guest'])->group(static function (): void {
Route::view('login', 'app.auth.login')->name('login');
Route::get(
'login/{email}',
LoginController::class,
)->middleware('signed')->name('login:store');
 
Route::view('register', 'app.auth.register')->name('register');
});

同样,我们使用 Livewire 组件用于注册表单 - 就像我们在登录过程中所做的那样。

final class RegisterForm extends Component
{
public string $name = '';
 
public string $email = '';
 
public string $status = '';
 
public function submit(CreateNewUser $user, SendLoginLink $action): void
{
$this->validate();
 
$user = $user->handle(
name: $this->name,
email: $this->email,
);
 
if (! $user) {
throw ValidationException::withMessages(
messages: [
'email' => 'Something went wrong, please try again later.',
],
);
}
 
$action->handle(
email: $this->email,
);
 
$this->status = 'An email has been sent for you to log in.';
}
 
public function rules(): array
{
return [
'name' => [
'required',
'string',
'min:2',
'max:55',
],
'email' => [
'required',
'email',
]
];
}
 
public function render(): View
{
return view('livewire.auth.register-form');
}
}

我们捕获用户的姓名、电子邮件地址,并具有一个状态属性,而不是再次使用请求会话。同样,我们使用一个 rules 方法来返回此请求的验证规则。我们回到 submit 方法,这一次,我们希望注入两个操作。

CreateNewUser 是我们用来根据提供的 信息创建并返回新用户的操作。如果由于某种原因失败,我们会在电子邮件上抛出一个验证异常。然后,我们使用我们在登录表单上使用的 SendLoginLink 操作来最大限度地减少代码重复。

final class CreateNewUser
{
public function handle(string $name, string $email): Builder|Model
{
return User::query()->create([
'name' => $name,
'email' => $email,
]);
}
}

我们可以重命名登录存储路由,但从技术上来说,我们正在再次执行此操作。我们创建了一个用户。然后我们希望登录用户。

这是您可采取的众多方法之一来实现无密码身份验证,但这是一种可行的方法。您可以在 此处找到 GitHub 存储库,如果您认为可以改进它,请随时提交 PR!

Steve McDougall photo

技术作家,就职于 Laravel 新闻,开发者布道师,就职于 Treblle。API 专家,经验丰富的 PHP/Laravel 工程师。 YouTube 直播主

Cube

Laravel 新闻稿

加入 40,000 多位其他开发者,永远不会错过新的提示、教程等。

Laravel Forge logo

Laravel Forge

轻松创建和管理您的服务器,并在几秒钟内部署您的 Laravel 应用程序。

Laravel Forge
Tinkerwell logo

Tinkerwell

Laravel 开发人员必备的代码运行器。使用 AI、自动完成和对本地和生产环境的即时反馈进行修补。

Tinkerwell
No Compromises logo

没有妥协

Joel 和 Aaron,两位来自“没有妥协”播客的经验丰富的开发者,现在可以为您的 Laravel 项目提供服务。⬧ 统一费率为每月 7500 美元。

没有妥协
Kirschbaum logo

Kirschbaum

提供创新和稳定性,以确保您的 Web 应用程序成功。

Kirschbaum
Shift logo

Shift

运行旧版本的 Laravel?即时、自动化的 Laravel 升级和代码现代化,让您的应用程序保持新鲜。

Shift
Bacancy logo

Bacancy

让经验丰富的 Laravel 开发人员(4-6 年经验)每月只需 2500 美元,即可为您的项目增光添彩。获得 160 小时的专用专业知识和 15 天的无风险试用。立即预约电话!

Bacancy
Lucky Media logo

Lucky Media

立即获得好运 - Laravel 开发的理想选择,拥有超过十年的经验!

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel 电子商务

Laravel 的电子商务。一个开源软件包,将现代无头电子商务功能的力量带到 Laravel。

Lunar: Laravel 电子商务
LaraJobs logo

LaraJobs

官方 Laravel 工作板

LaraJobs
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS 启动工具包

SaaSykit 是一个 Laravel SaaS 启动工具包,包含运行现代 SaaS 所需的所有功能。支付、精美结账、管理面板、用户仪表板、身份验证、即用型组件、统计、博客、文档等等。

SaaSykit: Laravel SaaS 启动工具包
Rector logo

Rector

您的无缝 Laravel 升级合作伙伴,降低成本,加速创新,助您的企业取得成功

Rector
MongoDB logo

MongoDB

通过 MongoDB 和 Laravel 的强大集成增强您的 PHP 应用程序,使开发人员能够轻松高效地构建应用程序。支持事务、搜索、分析和移动用例,同时使用熟悉的 Eloquent API。了解 MongoDB 的灵活、现代数据库如何改变您的 Laravel 应用程序。

MongoDB
Maska is a Simple Zero-dependency Input Mask Library image

Maska 是一个简单的零依赖输入掩码库

阅读文章
Add Swagger UI to Your Laravel Application image

将 Swagger UI 添加到您的 Laravel 应用程序

阅读文章
Assert the Exact JSON Structure of a Response in Laravel 11.19 image

在 Laravel 11.19 中断言响应的精确 JSON 结构

阅读文章
Build SSH Apps with PHP and Laravel Prompts image

使用 PHP 和 Laravel 提示构建 SSH 应用程序

阅读文章
Building fast, fuzzy site search with Laravel and Typesense image

使用 Laravel 和 Typesense 构建快速、模糊的网站搜索

阅读文章
Add Comments to your Laravel Application with the Commenter Package image

使用 Commenter 软件包向您的 Laravel 应用程序添加评论

阅读文章