Cara Membuat Login dan Register dengan Verifikasi Email di Laravel 11
1. Setup dan Konfigurasi Project
1.1 Setup Project dengan Composer
Selanjutnya kita akan install laravel kita, disini gua akan install atau membuat project dengan nama sruputkode-auth.
composer create-project laravel/laravel="11.*" sruputkode-auth
perintah diatas akan menginstall laravel versi 11 terkahir sobs, dimana pas gua install versinya yaitu v11.6.11.2 Konfigurasi File .env
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:4EKV5uMLfjy/tKTlH/T2aUW4VRpIW63hpAujIBdNpHc=
APP_DEBUG=true
APP_TIMEZONE=Asia/Jakarta
APP_URL=http://localhost
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database
PHP_CLI_SERVER_WORKERS=4
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=sruputkode-auth
DB_USERNAME=root
DB_PASSWORD=
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database
CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=sandbox.smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=USERNAME_MAIL_SOBS_SOBS
MAIL_PASSWORD=PASSWORD_SOBS_SOBS
MAIL_FROM_ADDRESS="admin@sruputkode.com"
MAIL_FROM_NAME="Sruputkode"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
Sesuaikan pengaturan MAIL dengan akun sobs-sobs di yang sudah terdaftar di mailtrap.io seperti dibawah ini :2. Konfigurasi Model User
<?php
namespace App\Models;
// Tambahkan Trait ini sobs MustVerifyEmail
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
// Implements trait MustVerifyEmail ke class User
class User extends Authenticatable implements MustVerifyEmail
{
// Use Notifiable
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
untuk konfigurasi User model sudah selesai sobs.3. Buat Controller dan Method
3.1 Buat AuthController
php artisan make:controller AuthController
3.2 Buat Beberapa Method di Auth Controller
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Auth\EmailVerificationRequest;
class AuthController extends Controller
{
public function login()
{
return view('auth.login');
}
public function loginAction(Request $request)
{
$credentials = $request->validate([
'email' => 'required|email',
'password' => 'required'
]);
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return redirect()->route('home');
}
return back()->with('error', 'Invalid Credentials, Please Try again !!!');
}
public function register()
{
return view('auth.register');
}
public function registerAction(Request $request)
{
$validate = $request->validate([
'name' => 'required',
'email' => 'required|email|unique:users,email',
'password' => 'required',
'password_confirm' => 'required|same:password',
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password)
]);
event(new Registered($user));
Auth::login($user);
return redirect()->route('verification.notice');
}
public function emailVerificationNotice()
{
if (Auth::user()->hasVerifiedEmail()) {
return redirect()->route('home');
}
return view('auth.verify-email');
}
public function emailVerify(EmailVerificationRequest $request)
{
$request->fulfill();
return redirect()->route('home');
}
public function logoutAction(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('login');
}
}
Yo kita breakdown methode diatas sobs :*login() : method ini hanya akan mengembalikan views untuk halaman login.
*loginAction() : method ini akan memproses login, dimana nantinya input email dan password akan dilakukan authentifikasi. jika berhasil maka akan membuat session baru kemudian diteruskan atau diredirect ke route home. di method ini gua juga menambahkan validasi untuk input email dan password. dimana email validasinya required dan email sedangkan password gua hanya required aja sobs.
*register() : sama seperti method login, method ini hanya akan mengembalikan views untuk register user sobs. jadi tidak ada logic sama sekali.
*registerAction() : method ini yang akan memproses register sobs. dimana jika user sudah melewati validasi register maka akan membuat sebuah data user baru. berikutnya user tersebut akan mendapatkan email verifikasi. untuk mengirimkan verifikasi email di handle oleh event Registered. setelah selesai mengirimkan email maka selanjutnya kita akan membuat user login dan me redirect ke route verification.notice dimana route ini akan menampilkan halaman pemberitahuan ke user bahwa email sudah dikirimkan.
*emailVerificationNotice() : adalah method yang menampilkan pesan kepada user untuk mengecek emailnya karena link verifikasi sudah dikirimkan. method ini adalah tahapan setelah user berhasil registrasi atau setelah method registerAction(). oh iya disini gua tambahkan kondisional jika si user sudah melakukan verifikasi maka route tidak bisa diakses dan otomatis meredirect user ke route home.
*emailVerify() : method ini digunakan untuk memverifikasi link yang sudah dikirimkan ke email user setelah registrasi. jika user sudah mengklik email verifikasi maka user akan di redirect ke route home sebagai bertanda bahwa verifikasi berhasil dilakukan.
*logout() : selanjutnya method ini berfungsi untuk menghandle proses logout user.
Sekarang kita lanjut controller lainnya.
3.3 Buat AppController
php artisan make:controller AppController
Jika sudah silahkan buka filenya sobs.3.4 Buat Method di AppController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AppController extends Controller
{
public function index()
{
$data = [
'name' => auth()->user()->name,
];
return view('app.index', $data);
}
}
dimana gua disini hanya menambahkan hanya satu method dimana method index ini hanya menampilkan halaman saja setelah user berhasil login. disini gua hanya mengirimkan data berupa nama dari user yang berhasil login.3. Membuat Tampilan
3.1 Buat Folder
3.2 Buat Base View
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>
@yield('title')
</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
@yield('content')
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous">
</script>
</body>
</html>
Jika sudah maka struktunya folder dan file nya akan seperti dibawah ini :3.2 Buat Register, Login dan Verify Email View
@extends('base.main')
@section('title')
Register
@endsection
@section('content')
<div class="bg-light py-3 py-md-5">
<div class="container">
<div class="row justify-content-md-center">
<div class="col-12 col-md-5 col-lg-5 col-xl-5 col-xxl-5">
<div class="bg-white p-4 p-md-5 rounded shadow-sm">
<div class="row">
<div class="col-12">
<h3 class="text-center mb-2">Register</h3>
</div>
</div>
<form action="{{ route('registerAction') }}" method="post">
@csrf
<div class="row gy-3 gy-md-4 overflow-hidden">
<div class="col-12">
<label for="name" class="form-label">Your Name <span
class="text-danger">*</span></label>
<div class="input-group">
<span class="input-group-text">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
fill="currentColor" class="bi bi-person-add" viewBox="0 0 16 16">
<path
d="M12.5 16a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7m.5-5v1h1a.5.5 0 0 1 0 1h-1v1a.5.5 0 0 1-1 0v-1h-1a.5.5 0 0 1 0-1h1v-1a.5.5 0 0 1 1 0m-2-6a3 3 0 1 1-6 0 3 3 0 0 1 6 0M8 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4" />
<path
d="M8.256 14a4.5 4.5 0 0 1-.229-1.004H3c.001-.246.154-.986.832-1.664C4.484 10.68 5.711 10 8 10q.39 0 .74.025c.226-.341.496-.65.804-.918Q8.844 9.002 8 9c-5 0-6 3-6 4s1 1 1 1z" />
</svg>
</span>
<input value="{{ old('name') }}" type="text"
class="form-control @error('name')
is-invalid
@enderror"
name="name" id="name">
@error('name')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</div>
</div>
<div class="col-12">
<label for="email" class="form-label">Email <span
class="text-danger">*</span></label>
<div class="input-group">
<span class="input-group-text">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
fill="currentColor" class="bi bi-envelope" viewBox="0 0 16 16">
<path
d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V4Zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1H2Zm13 2.383-4.708 2.825L15 11.105V5.383Zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741ZM1 11.105l4.708-2.897L1 5.383v5.722Z" />
</svg>
</span>
<input value="{{ old('email') }}" type="email"
class="form-control @error('email')
is-invalid
@enderror"
name="email" id="email">
@error('email')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</div>
</div>
<div class="col-12">
<label for="password" class="form-label">Password <span
class="text-danger">*</span></label>
<div class="input-group">
<span class="input-group-text">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
fill="currentColor" class="bi bi-key" viewBox="0 0 16 16">
<path
d="M0 8a4 4 0 0 1 7.465-2H14a.5.5 0 0 1 .354.146l1.5 1.5a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0L13 9.207l-.646.647a.5.5 0 0 1-.708 0L11 9.207l-.646.647a.5.5 0 0 1-.708 0L9 9.207l-.646.647A.5.5 0 0 1 8 10h-.535A4 4 0 0 1 0 8zm4-3a3 3 0 1 0 2.712 4.285A.5.5 0 0 1 7.163 9h.63l.853-.854a.5.5 0 0 1 .708 0l.646.647.646-.647a.5.5 0 0 1 .708 0l.646.647.646-.647a.5.5 0 0 1 .708 0l.646.647.793-.793-1-1h-6.63a.5.5 0 0 1-.451-.285A3 3 0 0 0 4 5z" />
<path d="M4 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
</svg>
</span>
<input type="password"
class="form-control @error('password')
is-invalid
@enderror"
name="password" id="password">
@error('password')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</div>
</div>
<div class="col-12">
<label for="password_confirm" class="form-label">Confirm Password <span
class="text-danger">*</span></label>
<div class="input-group">
<span class="input-group-text">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
fill="currentColor" class="bi bi-key" viewBox="0 0 16 16">
<path
d="M0 8a4 4 0 0 1 7.465-2H14a.5.5 0 0 1 .354.146l1.5 1.5a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0L13 9.207l-.646.647a.5.5 0 0 1-.708 0L11 9.207l-.646.647a.5.5 0 0 1-.708 0L9 9.207l-.646.647A.5.5 0 0 1 8 10h-.535A4 4 0 0 1 0 8zm4-3a3 3 0 1 0 2.712 4.285A.5.5 0 0 1 7.163 9h.63l.853-.854a.5.5 0 0 1 .708 0l.646.647.646-.647a.5.5 0 0 1 .708 0l.646.647.646-.647a.5.5 0 0 1 .708 0l.646.647.793-.793-1-1h-6.63a.5.5 0 0 1-.451-.285A3 3 0 0 0 4 5z" />
<path d="M4 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
</svg>
</span>
<input type="password"
class="form-control @error('password_confirm')
is-invalid
@enderror"
name="password_confirm" id="password_confirm">
@error('password_confirm')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</div>
</div>
<div class="col-12">
<div class="d-grid">
<button class="btn btn-primary btn-md" type="submit">Register</button>
</div>
</div>
</div>
</form>
<div class="row">
<div class="col-12">
<hr class="mt-5 mb-4 border-secondary-subtle">
<div class="d-flex flex-column flex-md-row justify-content-md-center">
<a href="{{ route('login') }}" class="link-secondary text-decoration-none">Have an
account</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('base.main')
@section('title')
Login Page
@endsection
@section('content')
<div class="bg-light py-3 py-md-5">
<div class="container">
<div class="row justify-content-md-center">
<div class="col-12 col-md-5 col-lg-5 col-xl-5 col-xxl-5">
<div class="bg-white p-4 p-md-5 rounded shadow-sm">
<div class="row">
<div class="col-12">
<h3 class="text-center mb-2">Login</h3>
</div>
</div>
@if (session('error'))
<div class="alert alert-danger alert-dismissible fade show text-sm" role="alert">
<small class="d-block text-center">
<strong>Error! </strong> {{ session('error') }}
</small>
<button type="button" class="btn-close" data-bs-dismiss="alert"
aria-label="Close"></button>
</div>
@endif
<form action="{{ route('loginAction') }}" method="post">
@csrf
<div class="row gy-3 gy-md-4 overflow-hidden">
<div class="col-12">
<label for="email" class="form-label">Email <span
class="text-danger">*</span></label>
<div class="input-group">
<span class="input-group-text">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
fill="currentColor" class="bi bi-envelope" viewBox="0 0 16 16">
<path
d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V4Zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1H2Zm13 2.383-4.708 2.825L15 11.105V5.383Zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741ZM1 11.105l4.708-2.897L1 5.383v5.722Z" />
</svg>
</span>
<input value="{{ old('email') }}" type="email"
class="form-control @error('email')
is-invalid
@enderror"
name="email" id="email" required>
@error('email')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</div>
</div>
<div class="col-12">
<label for="password" class="form-label">Password <span
class="text-danger">*</span></label>
<div class="input-group">
<span class="input-group-text">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
fill="currentColor" class="bi bi-key" viewBox="0 0 16 16">
<path
d="M0 8a4 4 0 0 1 7.465-2H14a.5.5 0 0 1 .354.146l1.5 1.5a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0L13 9.207l-.646.647a.5.5 0 0 1-.708 0L11 9.207l-.646.647a.5.5 0 0 1-.708 0L9 9.207l-.646.647A.5.5 0 0 1 8 10h-.535A4 4 0 0 1 0 8zm4-3a3 3 0 1 0 2.712 4.285A.5.5 0 0 1 7.163 9h.63l.853-.854a.5.5 0 0 1 .708 0l.646.647.646-.647a.5.5 0 0 1 .708 0l.646.647.646-.647a.5.5 0 0 1 .708 0l.646.647.793-.793-1-1h-6.63a.5.5 0 0 1-.451-.285A3 3 0 0 0 4 5z" />
<path d="M4 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0z" />
</svg>
</span>
<input type="password"
class="form-control @error('password')
is-invalid
@enderror"
name="password" id="password" value="" required>
@error('password')
{{ $message }}
@enderror
</div>
</div>
<div class="col-12">
<div class="d-grid">
<button class="btn btn-primary btn-md" type="submit">Log In</button>
</div>
</div>
</div>
</form>
<div class="row">
<div class="col-12">
<hr class="mt-5 mb-4 border-secondary-subtle">
<div class="d-flex flex-column flex-md-row justify-content-md-center">
<a href="{{ route('register') }}" class="link-secondary text-decoration-none">Create new
account</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@extends('base.main')
@section('title')
Check Email !!!
@endsection
@section('content')
<div class="bg-light py-3 py-md-5">
<div class="container">
<div class="row justify-content-md-center">
<div class="col-12 col-md-5 col-lg-5 col-xl-5 col-xxl-5">
<h3>Please !! Check Your Email for Activate Account.</h3>
</div>
</div>
</div>
</div>
@endsection
Struktur akhir folder dan filenya seperti dibawah ini :3.3 Buat App View
@extends('base.main')
@section('title')
App Dsahboard
@endsection
@section('content')
<div class="bg-light py-3 py-md-5">
<div class="container">
<div class="row justify-content-md-center">
<div class="col-12 col-md-5 col-lg-5 col-xl-5 col-xxl-5">
<h3 class="mb-3">Hello,</h3>
<h4 class="mb-3">Welcome, {{ $name }}</h4>
<form action="{{ route('logout') }}" method="post">
@csrf
<button class="btn btn-primary btn-sm" type="submit">Logout</button>
</form>
</div>
</div>
</div>
</div>
@endsection
untuk struktur folder dan file setelah semuanya view akan seperti dibawah ini sobs :4. Konfigurasi Route
<?php
use App\Http\Controllers\AppController;
use App\Http\Controllers\AuthController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::middleware('guest')->group(function () {
Route::get('/login', [AuthController::class, 'login'])->name('login');
Route::post('/login', [AuthController::class, 'loginAction'])->name('loginAction');
Route::get('/register', [AuthController::class, 'register'])->name('register');
Route::post('/register', [AuthController::class, 'registerAction'])->name('registerAction');
});
Route::get('/email/verify', [AuthController::class, 'emailVerificationNotice'])
->middleware('auth')->name('verification.notice');
Route::get('/email/verify/{id}/{hash}', [AuthController::class, 'emailVerify'])
->middleware(['auth', 'signed'])->name('verification.verify');
Route::middleware('auth', 'verified')->group(function () {
Route::get('/app', [AppController::class, 'index'])->name('home');
// Logout
Route::post('/logout', [AuthController::class, 'logoutAction'])->name('logout');
});
Oke untuk route sudah selesai.5. Migrasi Database & Jalankan aplikasi
php artisan migrate
dan kita jalankan Laravelnya.
php artisan serve
Oke Selanjutnya kita test.
Posting Komentar untuk "Cara Membuat Login dan Register dengan Verifikasi Email di Laravel 11"
Posting Komentar