」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 掌握 Laravel 密碼重設自訂:綜合指南

掌握 Laravel 密碼重設自訂:綜合指南

發佈於2024-11-08
瀏覽:685

Mastering Laravel Password Reset Customization: A Comprehensive Guide

Introduction

Password reset functionality is a critical component of any modern web application. While Laravel provides a robust out-of-the-box solution, there are times when you need to tailor this process to meet specific requirements or enhance user experience. In this tutorial, we'll dive deep into customizing Laravel's password reset workflow, covering everything from basic modifications to advanced techniques.

A Brief History of Laravel Authentication

Before we delve into customization, let's take a quick trip down memory lane to understand how Laravel's authentication solutions have evolved:

  1. Laravel UI: The first iteration of a complete auth solution in Laravel, which served the community well for years.
  2. Laravel Breeze: Born out of the growing popularity of Tailwind CSS, Breeze offered a minimal, lightweight, and modern authentication scaffolding.
  3. Laravel Jetstream: For those needing more advanced features, Jetstream was introduced, covering a wide range of authentication including 2FA and team management functionalities.
  4. Laravel Fortify: A headless authentication backend that can be used with any frontend, providing flexibility for developers to implement their own UI.

Understanding Laravel's Password Reset Flow

Laravel's password reset process typically involves the following steps:

  1. User requests a password reset
  2. A token is generated and stored
  3. An email is sent to the user with a reset link (signed URL)
  4. User clicks the link and enters a new password
  5. The password is updated, and the token is invalidated

While this flow works well for most applications, you might want to customize various aspects of this process to better suit your needs.

What We're Building

In this tutorial, we'll create a bare Laravel SaaS (minimal) application with a customized password reset flow. We'll cover:

  • Setting up a fresh Laravel application with Breeze
  • Customizing the password reset URL
  • Modifying the password reset email content
  • Adding a success notification after password reset
  • Implementing and customizing automated tests for our changes

Getting Started

Let's begin by setting up a new Laravel application:

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

Before we proceed, let's initialize Git for version control:

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

Now, let's install Laravel Breeze to get the basic authentication scaffolding:

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

When prompted, choose the stack that best fits your needs. For this tutorial, we'll use 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

After installation, let's commit our changes:

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

Now, set up your database and run migrations:

php artisan migrate

Install and compile your frontend assets:

npm install
npm run dev

At this point, we have a basic Laravel application with authentication functionality. Let's run the tests to ensure everything is working as expected:

php artisan test

You should see all tests passing, giving us a green light to proceed with our customizations.

Customizing the Password Reset URL

By default, Laravel (using Breeze) uses a standard URL for password reset (/reset-password). Let's customize this in our AppServiceProvider:

 $token,
                'email' => $user->getEmailForPasswordReset(),
            ], false));
        });
    }
}

This customization allows you to modify the reset URL structure, add additional parameters, or even point to a completely different domain if needed. For example, you could change it to:

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

Modifying the Password Reset Email

Next, let's customize the content of the password reset email. We'll do this by adding to our 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");
    });
}

Note: The __() function is a helper for localization, allowing easy translation of strings in your application.

Adding a Password Reset Success Notification

To enhance user experience and security, let's add a notification that's sent after a successful password reset. First, create a new notification:

php artisan make:notification PasswordResetSuccessfullyNotification

Edit the newly created notification:

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!');
    }
}

Now, create a listener for the PasswordReset event:

php artisan make:listener SendPasswordResetSuccessfullyNotification --event=PasswordReset

Update the listener:

user->notify(new PasswordResetSuccessfullyNotification());
    }
}

Remember to register this listener in your EventServiceProvider.

Testing Our Customizations

Testing is crucial to ensure our customizations work as expected. Update the existing password reset test in tests/Feature/Auth/PasswordResetTest.php:

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!

版本聲明 本文轉載於:https://dev.to/alphaolomi/mastering-laravel-password-reset-customization-a-comprehensive-guide-24p3?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 如何高效地在一個事務中插入數據到多個MySQL表?
    如何高效地在一個事務中插入數據到多個MySQL表?
    mySQL插入到多個表中,該數據可能會產生意外的結果。雖然似乎有多個查詢可以解決問題,但將從用戶表的自動信息ID與配置文件表的手動用戶ID相關聯提出了挑戰。 使用Transactions和last_insert_id() 插入用戶(用戶名,密碼)值('test','tes...
    程式設計 發佈於2025-07-13
  • 反射動態實現Go接口用於RPC方法探索
    反射動態實現Go接口用於RPC方法探索
    在GO 使用反射來實現定義RPC式方法的界面。例如,考慮一個接口,例如:鍵入myService接口{ 登錄(用戶名,密碼字符串)(sessionId int,錯誤錯誤) helloworld(sessionid int)(hi String,錯誤錯誤) } 替代方案而不是依靠反射...
    程式設計 發佈於2025-07-13
  • CSS可以根據任何屬性值來定位HTML元素嗎?
    CSS可以根據任何屬性值來定位HTML元素嗎?
    靶向html元素,在CSS 中使用任何屬性值,在CSS中,可以基於特定屬性(如下所示)基於特定屬性的基於特定屬性的emants目標元素: 字體家庭:康斯拉斯(Consolas); } 但是,出現一個常見的問題:元素可以根據任何屬性值而定位嗎?本文探討了此主題。 的目標元素有任何任何屬性值,...
    程式設計 發佈於2025-07-13
  • Java數組中元素位置查找技巧
    Java數組中元素位置查找技巧
    在Java數組中檢索元素的位置 利用Java的反射API將數組轉換為列表中,允許您使用indexof方法。 (primitives)(鏈接到Mishax的解決方案) 用於排序陣列的數組此方法此方法返回元素的索引,如果發現了元素的索引,或一個負值,指示應放置元素的插入點。
    程式設計 發佈於2025-07-13
  • 在JavaScript中如何並發運行異步操作並正確處理錯誤?
    在JavaScript中如何並發運行異步操作並正確處理錯誤?
    同意操作execution 在執行asynchronous操作時,相關的代碼段落會遇到一個問題,當執行asynchronous操作:此實現在啟動下一個操作之前依次等待每個操作的完成。要啟用並發執行,需要進行修改的方法。 第一個解決方案試圖通過獲得每個操作的承諾來解決此問題,然後單獨等待它們: c...
    程式設計 發佈於2025-07-13
  • 如何使用組在MySQL中旋轉數據?
    如何使用組在MySQL中旋轉數據?
    在關係數據庫中使用mySQL組使用mySQL組進行查詢結果,在關係數據庫中使用MySQL組,轉移數據的數據是指重新排列的行和列的重排以增強數據可視化。在這裡,我們面對一個共同的挑戰:使用組的組將數據從基於行的基於列的轉換為基於列。 Let's consider the following ...
    程式設計 發佈於2025-07-13
  • \“(1)vs.(;;):編譯器優化是否消除了性能差異?\”
    \“(1)vs.(;;):編譯器優化是否消除了性能差異?\”
    答案: 在大多數現代編譯器中,while(1)和(1)和(;;)之間沒有性能差異。編譯器: perl: 1 輸入 - > 2 2 NextState(Main 2 -E:1)V-> 3 9 Leaveloop VK/2-> A 3 toterloop(next-> 8 last-> 9 ...
    程式設計 發佈於2025-07-13
  • 表單刷新後如何防止重複提交?
    表單刷新後如何防止重複提交?
    在Web開發中預防重複提交 在表格提交後刷新頁面時,遇到重複提交的問題是常見的。要解決這個問題,請考慮以下方法: 想像一下具有這樣的代碼段,看起來像這樣的代碼段:)){ //數據庫操作... 迴聲“操作完成”; 死(); } ? > ...
    程式設計 發佈於2025-07-13
  • 為什麼PYTZ最初顯示出意外的時區偏移?
    為什麼PYTZ最初顯示出意外的時區偏移?
    與pytz 最初從pytz獲得特定的偏移。例如,亞洲/hong_kong最初顯示一個七個小時37分鐘的偏移: 差異源利用本地化將時區分配給日期,使用了適當的時區名稱和偏移量。但是,直接使用DateTime構造器分配時區不允許進行正確的調整。 example pytz.timezone(&#...
    程式設計 發佈於2025-07-13
  • 如何同步迭代並從PHP中的兩個等級陣列打印值?
    如何同步迭代並從PHP中的兩個等級陣列打印值?
    同步的迭代和打印值來自相同大小的兩個數組使用兩個數組相等大小的selectbox時,一個包含country代碼的數組,另一個包含鄉村代碼,另一個包含其相應名稱的數組,可能會因不當提供了exply for for for the uncore for the forsion for for ytry...
    程式設計 發佈於2025-07-13
  • 如何在Java字符串中有效替換多個子字符串?
    如何在Java字符串中有效替換多個子字符串?
    在java 中有效地替換多個substring,需要在需要替換一個字符串中的多個substring的情況下,很容易求助於重複應用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    程式設計 發佈於2025-07-13
  • 如何在無序集合中為元組實現通用哈希功能?
    如何在無序集合中為元組實現通用哈希功能?
    在未訂購的集合中的元素要糾正此問題,一種方法是手動為特定元組類型定義哈希函數,例如: template template template 。 struct std :: hash { size_t operator()(std :: tuple const&tuple)const {...
    程式設計 發佈於2025-07-13
  • Java字符串非空且非null的有效檢查方法
    Java字符串非空且非null的有效檢查方法
    檢查字符串是否不是null而不是空的if (str != null && !str.isEmpty())Option 2: str.length() == 0For Java versions prior to 1.6, str.length() == 0 can be二手: if(str!= n...
    程式設計 發佈於2025-07-13
  • PHP未來:適應與創新
    PHP未來:適應與創新
    PHP的未來將通過適應新技術趨勢和引入創新特性來實現:1)適應云計算、容器化和微服務架構,支持Docker和Kubernetes;2)引入JIT編譯器和枚舉類型,提升性能和數據處理效率;3)持續優化性能和推廣最佳實踐。 引言在編程世界中,PHP一直是網頁開發的中流砥柱。作為一個從1994年就開始發展...
    程式設計 發佈於2025-07-13
  • 在Python中如何創建動態變量?
    在Python中如何創建動態變量?
    在Python 中,動態創建變量的功能可以是一種強大的工具,尤其是在使用複雜的數據結構或算法時,Dynamic Variable Creation的動態變量創建。 Python提供了幾種創造性的方法來實現這一目標。 利用dictionaries 一種有效的方法是利用字典。字典允許您動態創建密鑰並...
    程式設計 發佈於2025-07-13

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3