Custom reset password laravel jetstream

  • August 15, 2023
  • 186

Bạn đang sử dụng laravel jetstream version laravel 10? Bạn đang muốn chỉnh sửa lại email reset password, response khi update password? Đây là bài viết dành cho bạn!

Custom Email reset password

Laravel jetstream đã hỗ trợ sẵn chức năng reset password, nhưng nội dung của email là mặc định của laravel. Làm sao để chỉnh sửa lại nội dung này? Giải pháp cho chúng ta là tạo một notification mới, xử dụng notification mới để gửi email.

Create ResetPassword notification

Tạo ResetPassword notification sử dụng CLI sau.


php artisan make:notification ResetPassword

Sửa lại code notification reset password sẵn có của laravel jetstream. Code đang dùng hiện tại được viết trong file
Illuminate\Auth\Notifications\ResetPassword

 
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use App\Mail\SendEmailResetPassword;

class ResetPassword extends Notification
{
    use Queueable;

    /**
     * The password reset token.
     *
     * @var string
     */
    public $token;

    /**
     * The callback that should be used to create the reset password URL.
     *
     * @var (\Closure(mixed, string): string)|null
     */
    public static $createUrlCallback;

    /**
     * The callback that should be used to build the mail message.
     *
     * @var (\Closure(mixed, string): \Illuminate\Notifications\Messages\MailMessage)|null
     */
    public static $toMailCallback;

    /**
     * Create a notification instance.
     *
     * @param string $token
     * @return void
     */
    public function __construct($token)
    {
        $this->token = $token;
    }

    /**
     * Get the notification's channels.
     *
     * @param mixed $notifiable
     * @return array|string
     */
    public function via($notifiable)
    {
        return ['mail'];
    }

    /**
     * Build the mail representation of the notification.
     *
     * @param mixed $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        return (new SendEmailResetPassword($notifiable, $this->resetUrl($notifiable)))
            ->to($notifiable->email);
    }

    /**
     * Get the reset URL for the given notifiable.
     *
     * @param mixed $notifiable
     * @return string
     */
    protected function resetUrl($notifiable)
    {
        if (static::$createUrlCallback) {
            return call_user_func(static::$createUrlCallback, $notifiable, $this->token);
        }

        return url(route('password.reset', [
            'token' => $this->token,
            'email' => $notifiable->getEmailForPasswordReset(),
        ], false));
    }

    /**
     * Set a callback that should be used when creating the reset password button URL.
     *
     * @param \Closure(mixed, string): string $callback
     * @return void
     */
    public static function createUrlUsing($callback)
    {
        static::$createUrlCallback = $callback;
    }

    /**
     * Set a callback that should be used when building the notification mail message.
     *
     * @param \Closure(mixed, string): \Illuminate\Notifications\Messages\MailMessage $callback
     * @return void
     */
    public static function toMailUsing($callback)
    {
        static::$toMailCallback = $callback;
    }
}

Sửa email chúng ta chỉ cần update lại hàm toMail() là được.

Override notificaion reset password

Để ghi đè notification reset password chúng ta cần thêm hàm sau vào User model.


use App\Notifications\ResetPassword;

public function sendPasswordResetNotification($token)
{
        $this->notify(new ResetPassword($token));
}

Như vậy là mỗi lần reset password sẽ gọi đến notification chúng ta vừa tạo.

Custom content email reset password

Tạo một email mới để gửi email cho người dùng


php artisan make:mail SendEmailResetPassword

Nội dung email reset password mới.


<?php

namespace App\Mail;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;

class SendEmailResetPassword extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     * @param User $user
     * @param string $url
     */
    public function __construct(public User $user, public string $url)
    {
    }

    /**
     * Get the message envelope.
     */
    public function envelope(): Envelope
    {
        return new Envelope(
            subject: 'Reset password',
        );
    }

    /**
     * Get the message content definition.
     */
    public function content(): Content
    {
        return new Content(
            view: 'emails.reset-password',
        );
    }

    /**
     * Get the attachments for the message.
     *
     * @return array<int, \Illuminate\Mail\Mailables\Attachment>
     */
    public function attachments(): array
    {
        return [];
    }
}

Tạo nội dung email trong view emails.reset-password



    {{ $user->fullname }} bạn muốn reset password?
Click vào link bên dưới để đổi mật khẩu.
{{ $url }}

Như vậy là chúng ta đã chỉnh sửa lại email reset password thành công.

Custom response when update password

Khi update password thành công chúng mặc định laravel sẽ redirect về trang login. Nếu chúng ta muốn nó redirect ra trang khác thì cân custom lại response. Logic update password được viết trong controller Laravel\Fortify\Http\Controllers\NewPasswordController chúng ta chỉ việc tạo ra controller mới và lấy lại code cũ sau đó chỉnh sử lại response là được


<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Contracts\Auth\StatefulGuard;
use Laravel\Fortify\Contracts\ResetPasswordViewResponse;
use Laravel\Fortify\Contracts\ResetsUserPasswords;
use Laravel\Fortify\Actions\CompletePasswordReset;
use Laravel\Fortify\Contracts\FailedPasswordResetResponse;
use App\Http\Responses\Contracts\PasswordResetResponse;
use Laravel\Fortify\Fortify;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Support\Facades\Password;
use Illuminate\Contracts\Auth\PasswordBroker;

class NewPasswordController extends Controller
{
    /**
     * The guard implementation.
     *
     * @var \Illuminate\Contracts\Auth\StatefulGuard
     */
    protected $guard;

    /**
     * Create a new controller instance.
     *
     * @param \Illuminate\Contracts\Auth\StatefulGuard $guard
     * @return void
     */
    public function __construct(StatefulGuard $guard)
    {
        $this->guard = $guard;
    }

    /**
     * Show the new password view.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Laravel\Fortify\Contracts\ResetPasswordViewResponse
     */
    public function create(Request $request): ResetPasswordViewResponse
    {
        return app(ResetPasswordViewResponse::class);
    }

    /**
     * Reset the user's password.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Contracts\Support\Responsable
     */
    public function store(Request $request): Responsable
    {
        $request->validate([
            'token' => 'required',
            Fortify::email() => 'required|email',
            'password' => 'required',
        ]);

        // Here we will attempt to reset the user's password. If it is successful we
        // will update the password on an actual user model and persist it to the
        // database. Otherwise we will parse the error and return the response.
        $status = $this->broker()->reset(
            $request->only(Fortify::email(), 'password', 'password_confirmation', 'token'),
            function ($user) use ($request) {
                app(ResetsUserPasswords::class)->reset($user, $request->all());

                app(CompletePasswordReset::class)($this->guard, $user);
            }
        );

        // If the password was successfully reset, we will redirect the user back to
        // the application's home authenticated view. If there is an error we can
        // redirect them back to where they came from with their error message.
        return $status == Password::PASSWORD_RESET
            ? app(PasswordResetResponse::class, ['status' => $status])
            : app(FailedPasswordResetResponse::class, ['status' => $status]);
    }

    /**
     * Get the broker to be used during password reset.
     *
     * @return \Illuminate\Contracts\Auth\PasswordBroker
     */
    protected function broker(): PasswordBroker
    {
        return Password::broker(config('fortify.passwords'));
    }
}

Tạo mới PasswordResetResponse để xử lý redirect sang page mới. Tạo 1 response interface mới


<?php

namespace App\Http\Responses\Contracts;

use Illuminate\Contracts\Support\Responsable;

interface PasswordResetResponse extends Responsable
{
    //
}

Tạo mộ implement cho interface trên


<?php

namespace App\Http\Responses;

use Illuminate\Http\JsonResponse;
use App\Http\Responses\Contracts\PasswordResetResponse as PasswordResetResponseContract;
use Laravel\Fortify\Fortify;

class PasswordResetResponse implements PasswordResetResponseContract
{
    /**
     * The response status language key.
     *
     * @var string
     */
    protected $status;

    /**
     * Create a new response instance.
     *
     * @param string $status
     * @return void
     */
    public function __construct(string $status)
    {
        $this->status = $status;
    }

    /**
     * Create an HTTP response that represents the object.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function toResponse($request)
    {
        return $request->wantsJson()
                    ? new JsonResponse(['message' => trans($this->status)], 200)
                    : redirect(Fortify::redirects('password-reset', config('fortify.views', true) ? route('reset-password.success') : null))->with('status', trans($this->status));
    }
}

Trong hàm toResponse() chúng ta sẽ custom lại sau khi update password thành công cho redirect về trang /reset-password-success.

Tổng kết

Như vậy là chúng ta đã custom xong các tính năng quan trọng của follow reset password. Hi vọng bài viết sẽ giúp ích cho bạn. Thanks for reading....