首页  >  文章  >  后端开发  >  掌握 Laravel 密码重置自定义:综合指南

掌握 Laravel 密码重置自定义:综合指南

WBOY
WBOY原创
2024-09-01 06:31:39350浏览

Mastering Laravel Password Reset Customization: A Comprehensive Guide

介绍

密码重置功能是任何现代 Web 应用程序的关键组件。虽然 Laravel 提供了强大的开箱即用解决方案,但有时您需要定制此流程以满足特定要求或增强用户体验。在本教程中,我们将深入探讨自定义 Laravel 的密码重置工作流程,涵盖从基本修改到高级技术的所有内容。

Laravel 身份验证简史

在深入研究定制之前,让我们快速回顾一下 Laravel 的身份验证解决方案是如何演变的:

  1. Laravel UI:Laravel 中完整身份验证解决方案的第一次迭代,多年来为社区提供了良好的服务。
  2. Laravel Breeze:Breeze 诞生于 Tailwind CSS 的日益流行,提供了一个最小的、轻量级的、现代的身份验证脚手架。
  3. Laravel Jetstream:对于那些需要更高级功能的人,引入了 Jetstream,涵盖了广泛的身份验证,包括 2FA 和团队管理功能。
  4. Laravel Fortify:可与任何前端一起使用的无头身份验证后端,为开发人员实现自己的 UI 提供灵活性。

了解 Laravel 的密码重置流程

Laravel 的密码重置过程通常涉及以下步骤:

  1. 用户请求重置密码
  2. 生成并存储令牌
  3. 将向用户发送一封电子邮件,其中包含重置链接(签名 URL)
  4. 用户点击链接并输入新密码
  5. 密码已更新,令牌失效

虽然此流程适用于大多数应用程序,但您可能希望自定义此流程的各个方面以更好地满足您的需求。

我们正在建设什么

在本教程中,我们将创建一个带有自定义密码重置流程的裸 Laravel SaaS(最小)应用程序。我们将涵盖:

  • 使用 Breeze 设置新的 Laravel 应用程序
  • 自定义密码重置URL
  • 修改密码重置邮件内容
  • 添加密码重置后成功通知
  • 针对我们的更改实施和定制自动化测试

入门

让我们开始设置一个新的 Laravel 应用程序:

composer create-project laravel/laravel password-reset-demo
cd password-reset-demo

在继续之前,让我们初始化 Git 以进行版本控制:

git init
git add .
git commit -m "Initial commit"

现在,让我们安装 Laravel Breeze 来获取基本的身份验证脚手架:

composer require laravel/breeze --dev
php artisan breeze:install

出现提示时,选择最适合您需求的堆栈。在本教程中,我们将使用 Livewire:

php artisan breeze:install

  Which Breeze stack would you like to install?
❯ livewire

  Would you like dark mode support? (yes/no) [no]
❯ no

  Which testing framework do you prefer? [PHPUnit]
❯ Pest

安装后,让我们提交更改:

git add .
git commit -m "Add Authentication and Pages"

现在,设置数据库并运行迁移:

php artisan migrate

安装并编译您的前端资源:

npm install
npm run dev

此时,我们已经有了一个具有身份验证功能的基本 Laravel 应用程序。让我们运行测试以确保一切按预期工作:

php artisan test

您应该看到所有测试都通过了,为我们继续进行定制开了绿灯。

自定义密码重置 URL

默认情况下,Laravel(使用 Breeze)使用标准 URL 进行密码重置(/reset-password)。让我们在 AppServiceProvider 中自定义它:

<?php

namespace App\Providers;

use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        ResetPassword::createUrlUsing(function (User $user, string $token) {
            return url(route('password.reset', [
                'token' => $token,
                'email' => $user->getEmailForPasswordReset(),
            ], false));
        });
    }
}

此自定义允许您修改重置 URL 结构、添加其他参数,甚至根据需要指向完全不同的域。例如,您可以将其更改为:

return "https://account.yourdomain.com/reset-password?token={$token}&email={$user->getEmailForPasswordReset()}";

修改密码重置邮箱

接下来,让我们自定义密码重置电子邮件的内容。我们将通过添加到我们的 AppServiceProvider 来做到这一点:

use Illuminate\Notifications\Messages\MailMessage;

// ...

public function boot(): void
{
    // ... previous customizations

    ResetPassword::toMailUsing(function (User $user, string $token) {
        $url = url(route('password.reset', [
            'token' => $token,
            'email' => $user->getEmailForPasswordReset(),
        ], false));

        return (new MailMessage)
            ->subject(config('app.name') . ': ' . __('Reset Password Request'))
            ->greeting(__('Hello!'))
            ->line(__('You are receiving this email because we received a password reset request for your account.'))
            ->action(__('Reset Password'), $url)
            ->line(__('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.' . config('auth.defaults.passwords') . '.expire')]))
            ->line(__('If you did not request a password reset, no further action is required.'))
            ->salutation(__('Regards,') . "\n" . config('app.name') . " Team");
    });
}

注意:__() 函数是本地化的助手,可以轻松翻译应用程序中的字符串。

添加密码重置成功通知

为了增强用户体验和安全性,让我们添加在成功重置密码后发送的通知。首先,创建一个新通知:

php artisan make:notification PasswordResetSuccessfullyNotification

编辑新创建的通知:

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class PasswordResetSuccessfullyNotification extends Notification implements ShouldQueue
{
    use Queueable;

    public function via($notifiable)
    {
        return ['mail'];
    }

    public function toMail($notifiable)
    {
        return (new MailMessage)
            ->subject('Password Reset Successful')
            ->greeting('Hello!')
            ->line('Your password has been successfully reset.')
            ->line('If you did not reset your password, please contact support immediately.')
            ->action('Login to Your Account', url('/login'))
            ->line('Thank you for using our application!');
    }
}

现在,为PasswordReset事件创建一个监听器:

php artisan make:listener SendPasswordResetSuccessfullyNotification --event=PasswordReset

更新监听器:

<?php

namespace App\Listeners;

use App\Notifications\PasswordResetSuccessfullyNotification;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendPasswordResetSuccessfullyNotification implements ShouldQueue
{
    public function handle(PasswordReset $event)
    {
        $event->user->notify(new PasswordResetSuccessfullyNotification());
    }
}

请记住在您的 EventServiceProvider 中注册此侦听器。

测试我们的定制

测试对于确保我们的定制按预期工作至关重要。更新tests/Feature/Auth/PasswordResetTest.php中现有的密码重置测试:

<?php

namespace Tests\Feature\Auth;

use App\Models\User;
use App\Notifications\PasswordResetSuccessfullyNotification;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase;

class PasswordResetTest extends TestCase
{
    public function test_reset_password_link_can_be_requested(): void
    {
        Notification::fake();

        $user = User::factory()->create();

        $this->post('/forgot-password', ['email' => $user->email]);

        Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) {
            $response = $this->get($notification->toMail($user)->actionUrl);
            $this->assertStringContainsString('Reset Password', $response->getContent());
            return true;
        });
    }

    public function test_password_can_be_reset_with_valid_token(): void
    {
        Notification::fake();

        $user = User::factory()->create();

        $this->post('/forgot-password', ['email' => $user->email]);

        Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) {
            $token = $notification->token;

            $response = $this->post('/reset-password', [
                'token' => $token,
                'email' => $user->email,
                'password' => 'new-password',
                'password_confirmation' => 'new-password',
            ]);

            $response->assertSessionHasNoErrors();

            Notification::assertSentTo($user, PasswordResetSuccessfullyNotification::class);

            return true;
        });
    }

    public function test_reset_password_email_contains_custom_content(): void
    {
        Notification::fake();

        $user = User::factory()->create();

        $this->post('/forgot-password', ['email' => $user->email]);

        Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) {
            $mailMessage = $notification->toMail($user);
            $this->assertStringContainsString('Hello!', $mailMessage->greeting);
            $this->assertStringContainsString('Regards,', $mailMessage->salutation);
            return true;
        });
    }
}

Conclusion

Customizing Laravel's password reset workflow allows you to create a more tailored and user-friendly experience for your application. We've covered how to modify the reset URL, customize the email content, add a success notification, and ensure everything works through automated testing.

Remember, while customization can be powerful, it's essential to maintain security best practices throughout the process. Always validate user input, use secure token generation and storage methods, and follow Laravel's security recommendations.

Some additional considerations for further improvements:

  1. Implement rate limiting on password reset requests to prevent abuse.
  2. Add logging for successful and failed password reset attempts for security auditing.
  3. Consider implementing multi-channel notifications (e.g., SMS, push notifications) for critical security events like password resets.
  4. Regularly review and update your password policies to align with current security best practices.

For more advanced topics and Laravel insights, check out the official Laravel documentation and stay tuned to the Laravel community resources for more in-depth tutorials and best practices.

Happy coding, and may your Laravel applications be ever secure and user-friendly!

以上是掌握 Laravel 密码重置自定义:综合指南的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn