Xin chào tất cả mọi người, mình sẽ hướng dẫn mọi người làm chức năng gửi gmail xác thực người dùng bằng mã OTP giống như Facebook bằng Laravel 8x.Bài viết này dành cho người đã từng học qua Laravel cơ bản nên mọi người tự set up project Laravel nhé
1. Tạo mật khẩu ứng dụng trong gmail
B1.Đầu tiên bạn hãy đăng nhập vào gmail ấn vào avatar và vào mục quản lí ứng dụng
B2.Chọn tab bảo mật và chọn mật khẩu ứng dụng
B3.Chọn options như sau sẽ giúp bạn đăng nhập gmail mà không cần mật khẩu gốc
Một mật khẩu ứng dụng được sinh ra,chúng ta sẽ dùng mật khẩu này để thay thế cho mật khẩu gốc
2.Cấu hình file mail.php trong folder config và sửa .env
'smtp' => [
'transport' => 'smtp',
'host' => env('MAIL_HOST', 'smtp.gmail.com'),
'port' => env('MAIL_PORT', 587),
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'timeout' => null,
'auth_mode' => null,
],
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'yourmail@gmail.com'),
'name' => env('MAIL_FROM_NAME', 'Facebook'),
],
Ở đây bạn đã cấu hình laravel để gửi mail theo giao thức smtp và ở đoạn code dưới.Bạn đã xác nhận tất cả các thư gửi đi từ ứng dụng này là từ mail của bạn với tên mặc định là Facebook
Tiếp theo ở file env. hãy sửa 2 dòng này với mail là mail của bạn và password là password được tạo từ mật khẩu ứng dụng ở trên sửa
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=yourmail
MAIL_PASSWORD=password
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
thành
MAIL_USERNAME=yourgmail@gmail.com
MAIL_PASSWORD=yourpass
3.Tạo database với migration
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('first_name');
$table->string('last_name');
$table->string('gender');
$table->string('url')->default('https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcQjYmlp9JDeNMaFZzw9S3G1dVztGqF_2vq9nA&usqp=CAU&fbclid=IwAR2SQAloFwGL7-bZGs_T9QGN3INYsQXs1krNAuofn0qt7-vjfu-GPgIjYuA');
$table->string('background_url')->default('https://gamehot24h.com/wp-content/uploads/2019/12/photo-3-15705517650541283685351_1575536037.jpg');
$table->date('birth');
$table->string('email')->unique()->default(NULL);
$table->string('number_phone')->unique()->default(NULL);
$table->timestamp('email_verified_at')->nullable();
$table->boolean('confirm');
$table->string('confirmation_code')->default(NULL);
$table->dateTime('confirmation_code_expired_in')->default(NULL);
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Ở đây bạn chỉ cần quan tâm tới 3 trường là confirm là để kiểm tra xem tài khoản đã được xác thực hay chưa hay nói cách khác là người dùng đã nhập OTP xác thực thành công khi nhận đc từ mail chưa,thứ 2 là trường confirmation_code là đoạn mã nhận được sau khi người dùng đăng ký gmail và confirmation_code_expiredin là thời gian OTP hết hạn
4.Viết api trong file api.php
Route::post('/register', [AuthController::class, 'register']);
Route::post('/re_register', [AuthController::class, 're_register']);
Route::get('email/verify/{id}',[VerificationController::class,'verify'])->name('verification.verify');
Route::post('email/verify_OTP',[VerificationController::class,'verify_OTP']);
Route::post('email/logout_OTP',[VerificationController::class,'logout_OTP']);
/register: Khi người dùng ấn đăng ký sau khi nhập thông tin từ form
/re_register: Khi người dùng ấn gửi lại mã OTP
/email/verify_OTP: Sau khi người dùng ấn mã OTP
/email/logout_OTP: Hủy đăng ký
5.Tạo VerificationController.php
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
class VerificationController extends Controller
{
public function verify_OTP(Request $request)
{
$user = User::findOrFail($request->input('user_id'));
if (!$user) {
return response()->json(["status" => 400, "message" => "User doenst exist"], 400);
}
if (Carbon::now()->gt($user->confirmation_code_expired_in)) {
return response()->json(["status" => 400, "message" => "Your OTP expired"], 400);
} else {
if ($request->input('OTP_token') != $user->confirmation_code) {
return response()->json(["status" => 400, "message" => "Your OTP is invalid"], 400);
}
$user->confirm = true;
$user->save();
return response()->json(["status" => 200, "message" => "Succesfully verified"], 200);
}
}
public function logout_OTP(Request $request)
{
$user = User::findOrFail($request->input('user_id'));
if (!$user) {
return response()->json(["status" => 400, "message" => "User doenst exist"], 400);
}
if ($user->confirm == false) {
$result = $user->delete();
if ($result)
return response()->json(["status" => 200, "message" => "Succesfully logout in OTP screen"], 200);
else {
return response()->json(["status" => 400, "message" => "Logout failed in OTP screen"], 400);
}
}
return response()->json(["status" => 400, "message" => "Unauthorized"], 400);
}
}
5.2 Tạo AuthController.php
<?php
namespace App\Http\Controllers;
use App\Mail\UserVerification;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use Validator;
use Carbon\Carbon;
class AuthController extends Controller
{
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'first_name' => 'required|string|between:2,100',
'last_name' => 'required|string|between:2,100',
'number_phone' => 'string|between:10,20',
'birth' => 'required|string|between:10,20',
'gender' => 'required|string',
'email' => 'required|string|email|max:100',
'password' => 'required|string|min:6',
]);
if ($validator->fails()) {
return response()->json($validator->errors()->toJson(), 400);
}
$user = User::where('email', $request->email)->first();
if ($user) {
if ($user['confirm'] == true)
return response()->json([
'message' => 'Email existed',
], 401);
else {
return response()->json([
'message' => 'This api just use for registering the first time.Please use api re_register to reregister',
], 400);
}
}
$user = User::create(array_merge(
$validator->validated(),
[
'password' => bcrypt($request->password),
'confirm' => false,
'confirmation_code' => rand(100000, 999999),
'confirmation_code_expired_in' => Carbon::now()->addSecond(60)
]
));
try {
Mail::to($user->email)->send(new UserVerification($user));
return response()->json([
'message' => 'Registered,verify your email address to login',
'user' => $user
], 201);
} catch (\Exception $err) {
$user->delete();
return response()->json([
'message' => 'Could not send email verification,please try again',
], 500);
}
return response()->json([
'message' => 'Failed to create',
], 500);
}
public function re_register(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email|max:100',
// 'password' => 'string|min:6',
]);
if ($validator->fails()) {
return response()->json($validator->errors()->toJson(), 400);
}
$user = User::where('email', $request->email)->first();
if ($user) {
if ($user['confirm'] == true)
return response()->json([
'message' => 'Email existed',
], 401);
else {
$user->confirmation_code = rand(100000, 999999);
$user->confirmation_code_expired_in = Carbon::now()->addSecond(60);
$user->save();
try {
Mail::to($user->email)->send(new UserVerification($user));
return response()->json([
'message' => 'Registered again,verify your email address to login ',
'user' => $user
], 201);
} catch (\Exception $err) {
$user->delete();
return response()->json([
'message' => 'Could not send email verification,please try again',
], 500);
}
}
}
return response()->json([
'message' => 'Failed to re_register',
], 500);
}
}
Mặc định mã OTP sẽ có 6 số và thời gian hết hạn là 60s hàm re_register để reset lại OTP nhé
6.Tạo file markdown
Hãy chạy câu lệnh
php artisan make:mail UserVerification
trong đó :
<?php
namespace App\Mail;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class UserVerification extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* @return void
*/
public $user;
public function __construct(User $user)
{
$this->user=$user;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->markdown('email.name')->with(['OTP'=>$this->user->confirmation_code,'OTP_expired'=>$this->user->confirmation_code_expired_in]);
}
}
Ở đây dòng quan trọng nhất nằm ở function build :
$this->markdown('email.name')->with(['OTP'=>$this->user->confirmation_code,'OTP_expired'=>$this->user->confirmation_code_expired_in]);
email.name là đường dẫn của file markdown khi gửi mail với thư mục gốc là resources/views và hàm with để truyên mã OTP và expired _time vào file markdown .Ở đây là
Ở trong file resources/views/name.blade.php:
@component('mail::message')
# New generation
The body of your message.<br>
Welcome {{$user->last_name}}<br>
Your OTP is <strong style="color:'blue'">{{$OTP}}</strong> will be expired for 60 seconds
@component('mail::button')
Button Text
@endcomponent
Thanks,<br>
<strong style="color:'red'">Huy Tú and Mai Lâm</strong>
@endcomponent
File này sử dụng template của laravel nếu muốn sửa lại bạn hãy sử dụng php blade như thường nhé
7.Hưởng thụ thành quả nào
Phù !!,quả là vất vả đúng không nào giờ chúng ta sẽ sử dụng Postman để test xem sao nhé