Laravel หน้ารีเซ็ตรหัสผ่านไม่มี email

Laravel logo

ถ้าใครที่ใช้ laravel ตั้งแต่เวอร์ชั่น 5.0 เป็นต้นมาคงจะเจอเคสนี้กันเป็นประจำ โดยปกติแล้วเวลาเราใช้คำสั่ง

php artisan make:auth

เราจะได้ระบบพื้นฐานในการยืนยันตัวผู้ใช้เช่น ระบบ login, logout, register, forgotpassword, resetpassword

แต่ถ้าใครที่ลองเล่นจริงๆจะเจอปัญหาว่า เมื่อเราเข้าหน้าลืมรหัสผ่าน laravel จะให้กรอก email และกดยืนยันเพื่อรับ email ในการรีเซ็ตรหัสผ่านหน้าตาแบบนี้

พอกด send password reset link เราจะได้ email ที่มีลิงค์มาให้ประมานนี้

http://test.test/password/reset/b4eca5d17c644b6b46292bb8497093bd433a2e663191051334f7bf748aaf5ec0

หลังจากเรากดลิงค์นี้ใน email เราจะเจอกับหน้านี้

ซึ่งมันเจอแค่นี้จริงๆ แล้วช่องที่ให้กรอก email ทำไมมันถึงไม่มี email ของ user มันหายไปไหน ? Laravel ไม่ได้ทำมาให้นั่นเองเพราะเค้าคิดว่าแต่ละ project อาจจะนำไปใช้ไม่เหมือนกันเลยไม่ได้ใส่มาให้เรามาดูวิธีทำกันดีกว่า

ในส่วนของ doc ที่เขียนเกี่ยวกับเรื่องนี้มีอยู่นิดเดียวเล่นทำเอางงใครอยากอ่านตามลิงก์นี้เลย อยู่ล่างสุดของหน้าเลย

เอาละปัญหามันคือตอนที่ส่ง email ไปหา user เนี่ย laravel ไม่ได้แนบ email ไปกับ URL ทีนี้วิธีแก้ปัญหาก็เอา email แนบไปกับ URL แล้วตอนกด URL กลับมาก็สั่งให้มันไปอยู่ใน input ด้วยสิ ไม่เห็นจะยาก !! หายไป 30 นาที…..

ขั้นแรกให้เรา override method sendPasswordResetNotification ที่อยู่ใน model user ก่อน

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

ไอ้เจ้า method sendPasswordResetNotification เนี่ยมันไปเรียกใช้ notification mail ของ laravel อยู่เราต้องสร้าง noti เพื่อส่งเมลใหม่ที่เรา custom เองโดยการใช้คำสั่ง

php artisan make:notification ResetPasswordNotification

เราจะได้ไฟล์ที่ App\Notifications\ResetPasswordNotification.php

จากนั้นเพิ่ม code ตามนี้ครับ

public $token;
public function __construct($token) {
 $this->token = $token;
}
** สร้างตัวแปล $token ขึ้นมาก่อนหลังจากนั้นใน __construct รับ $token ส่งให้ $this->token อีกที

หลังจากนั้นเลื่อนลงไปหา method toMail แล้วเปลี่ยน code ตามด้านล่างนี้ครับ

public function toMail($notifiable) {
 return (new MailMessage)
  ->line('You are receiving this email because we received a password reset request for your account.')
  ->action('Reset Password', url(config('app.url') . route('password.reset', [$this->token, 'e' => encrypt($notifiable->email)], false)))
  ->line('If you did not request a password reset, no further action is required.');
}

ในส่วนของ action คือการสร้างปุ่มในเมลหน้าตาเมลที่ส่งไปจะเป็นแบบนี้

สังเกตุว่าตรง ->action เราเพิ่ม param ไปอีกตัวคือ

'e' => encrypt($notifiable->email)
** $notifiable คือตัวแปรที่ laravel โยน model ทั้งก้อนเข้ามาให้ถ้ายังจำกันได้เราสร้าง notification ตัวนี้ไว้ใน user model มันเลยโยน user คนนั้นกลับมาเราสามารถเรียก username, name, email หรืออื่นๆได้หมดเลยในที่นี้ผมเรียกแค่ email

จะสังเกตุได้ว่าผมเอาฟังก์ชั่น encrypt แปลงค่าของ email เพราะว่าเวลาอยู่ใน url มันจะไม่สวยครับมันจะกลายเป็นแบบนี้

http://test.test/password/reset/b4eca5d17c644b6b46292bb8497093bd433a2e663191051334f7bf748aaf5ec0?e=test%40test.com

คงไม่สวยแน่ๆแต่ถ้าแปลงแล้วจะกลายเป็นแบบนี้

http://test.test/password/reset/41d42e322245efaee37da9c2cfe452bd9242a5f34742bbebbd74657ac0afeb4b?e=eyJpdiI6Ik9VNnZIaVwvbEVoMlwvOVMwdDFoZmFiZz09IiwidmFsdWUiOiJNMHArV2pcL2tqOXRPMElHNllpbFJrN20rWFp1dXo0dEVTVXhXMG9PTVRmVT0iLCJtYWMiOiI2NTZiMGEyOWNjYjYxYWE3NGU0ZWFmMzkyYTE0MzJiYjY4MTk2OTc5MjMyZTJlMDdiZmE1NjYxNjRjNDE0ZjQ1In0

หลังจากนั้นให้ไปที่ App\Http\Controllers\Auth\ResetPasswordController.php
แล้ว override method showResetForm ของ ralavel อีกครั้งด้วย code นี้

public function showResetForm(Request $request, $token = null) {
 return view('auth.passwords.reset')->with(
  ['token' => $token, 'email' => decrypt($request->query('e'))]
 );
}
** ทำการแปลงค่าที่ได้จาก query string ด้วย decrypt ก็จะได้ email กลับมาแล้วส่งกลับไปหน้าฟอร์มที่เหลือเราไม่ต้องแก้อะไรครับ

พอเรากดลิงก์จากเมลกลับมาก็จะพบว่ามี email อยู่ในช่อง email ของ form เรียบร้อยแล้ว เราอาจจะไปเพิ่ม readonly ใน input เพื่อไม่ให้ user แก้ไขได้เท่านี้ก็เรียบร้อย

จริงๆหลายคนอาจจะไม่สนใจตรงส่วนนี้เพราะถ้า user กด URL มาก็ให้เค้ากรอกเมลอีกรอบสิจะเป็นอะไรไปแต่แน่นอนว่า UX ของโปรแกรมเราอาจจะไม่ดีนักเพราะ user ต้องมากรอกเองอีกรอบทำให้ user สบายๆเข้าไว้เค้าจะได้จ่ายตังแบบสบายๆให้เราด้วย ฮ่าๆๆ วันหน้าจะมี pain อะไรอย่าลืมติดตามกันครับ

สำหรับใครที่อยากส่งเมลออกจากระบบ Laravel แนะนำให้ใช้ SMTP Email Service จะส่งถึงมากกว่าใช้ SMTP ของ Share host มาดูวิธีการสมัคร Sendinblue SMTP กันครับ

เกี่ยวกับผู้เขียน

ITTHIPAT

สวัสดีครับผม อิทธิพัทธ์ (เป้) ชอบหาเทคนิคต่างๆที่ทำให้ชีวิต Programmer ง่ายขึ้น ทั้ง Automate, Library ชอบทำ Blog และ Video ถ้ามีเวลานะ!

ขอบคุณทุกคนที่ติดตาม และอ่านบทความของผมครับ ผมหวังว่าความรู้ที่เขียนขึ้นในเว็บไซต์นี้จะช่วยทุกท่านได้ไม่มากก็น้อย 

Scroll to Top