Di bagian sebelumnya kita sudah menguasai form dan validasi. Sekarang saatnya menambahkan fitur yang hampir semua aplikasi web butuhkan: sistem autentikasi. Membangun sistem login dari nol adalah pekerjaan yang panjang dan penuh potensi celah keamanan. Laravel Breeze hadir sebagai solusi — starter kit resmi Laravel yang menghasilkan kode autentikasi yang lengkap, aman, dan bisa dikustomisasi sepenuhnya hanya dalam beberapa menit.
💡 Ini adalah bagian kesembilan dari seri "Belajar Laravel dari Nol". Di bagian ini kita akan menginstal Laravel Breeze, memahami semua komponen autentikasi yang dihasilkan, dan mempelajari cara mengkustomisasinya sesuai kebutuhan aplikasi. Pastikan project Laravel kamu sudah berjalan dan database sudah terkonfigurasi dengan benar.
Pilihan Starter Kit Authentication Laravel
Laravel menyediakan beberapa pilihan starter kit untuk autentikasi, masing-masing dengan tingkat kompleksitas dan fitur yang berbeda. Memahami perbedaannya penting agar kamu memilih yang paling sesuai dengan kebutuhan project — jangan langsung pilih yang paling canggih jika project belum membutuhkannya.
─── PILIHAN AUTHENTICATION STARTER KIT ──────────────────
LARAVEL BREEZE (Direkomendasikan untuk pemula)
✓ Simple, minimal, mudah dipahami
✓ Kode yang dihasilkan bisa dikustomisasi bebas
✓ Pilihan stack: Blade, Livewire, Inertia (Vue/React)
✓ Fitur: login, register, forgot password,
email verification, profile update
✗ Tidak ada: teams, 2FA, API token management
Cocok untuk: aplikasi web standar, belajar Laravel
LARAVEL JETSTREAM (Lebih lengkap)
✓ Fitur lebih lengkap dari Breeze
✓ Multi-team support
✓ Two-factor authentication (2FA)
✓ API token management (via Sanctum)
✓ Profile photo upload
✗ Lebih kompleks, lebih sulit dikustomisasi
Cocok untuk: SaaS, aplikasi dengan tim dan API
LARAVEL FORTIFY (Headless)
✓ Backend authentication tanpa frontend
✓ Sangat fleksibel — buat UI sendiri
✗ Butuh lebih banyak setup
Cocok untuk: API-only atau custom UI
MANUAL (Tanpa starter kit)
✓ Kontrol penuh
✗ Harus build dari nol — rawan celah keamanan
✗ Tidak direkomendasikan kecuali ada alasan kuat
REKOMENDASI: Gunakan Laravel Breeze untuk
sebagian besar project, terutama saat belajar.
Instalasi Laravel Breeze
Proses instalasi Laravel Breeze sangat mudah — hanya butuh beberapa perintah dan semua file autentikasi langsung ter-generate di project kamu. Yang terpenting adalah memilih stack yang tepat saat proses instalasi, karena stack menentukan teknologi frontend yang digunakan untuk halaman autentikasi.
Tambahkan Laravel Breeze ke project menggunakan Composer sebagai development dependency. Breeze hanya dibutuhkan saat instalasi — setelah kode di-generate, package ini tidak lagi diperlukan untuk menjalankan aplikasi.
Perintah php artisan breeze:install akan meminta kamu memilih stack (Blade adalah pilihan paling sederhana untuk pemula), testing framework, dan beberapa opsi lainnya. Setelah memilih, Breeze men-generate semua file yang dibutuhkan.
Setelah file di-generate, install dependencies Node.js dengan npm install, kompilasi asset dengan npm run dev, dan jalankan migration untuk membuat tabel yang dibutuhkan autentikasi.
# ── LANGKAH 1: Install package ────────────────────────
composer require laravel/breeze --dev
# ── LANGKAH 2: Jalankan installer ─────────────────────
php artisan breeze:install
# Kamu akan ditanya beberapa pertanyaan:
# Which Breeze stack would you like to install?
# [blade] Blade with Alpine.js ← Pilih ini untuk pemula
# [livewire] Livewire with Alpine.js
# [livewire-functional] Livewire (Functional API)
# [react] Inertia with React
# [vue] Inertia with Vue
# [api] API only
#
# Would you like dark mode support? (yes/no) [no]
# Which testing framework do you prefer?
# [0] PHPUnit
# [1] Pest
# ── LANGKAH 3: Install & kompilasi asset ──────────────
npm install
npm run dev
# Atau untuk production: npm run build
# ── LANGKAH 4: Jalankan migration ─────────────────────
php artisan migrate
# Membuat tabel: users, password_reset_tokens,
# sessions, cache, jobs
# ── LANGKAH 5: Jalankan server ────────────────────────
php artisan serve
# Buka: http://localhost:8000
# Kamu akan melihat link Login dan Register di pojok kanan atas
File yang Dihasilkan Breeze
Setelah instalasi selesai, Breeze menghasilkan banyak file di berbagai lokasi. Memahami apa yang dihasilkan dan di mana letaknya adalah kunci untuk bisa mengkustomisasi autentikasi sesuai kebutuhan aplikasimu.
FILE YANG DIHASILKAN BREEZE (stack: blade):
app/Http/Controllers/Auth/
├── AuthenticatedSessionController.php ← Login & Logout
├── ConfirmablePasswordController.php ← Konfirmasi password
├── EmailVerificationNotificationController.php
├── EmailVerificationPromptController.php
├── NewPasswordController.php ← Reset password
├── PasswordController.php ← Update password
├── PasswordResetLinkController.php ← Forgot password
└── RegisteredUserController.php ← Register
app/Http/Requests/Auth/
└── LoginRequest.php ← Validasi + rate limiting login
resources/views/auth/
├── confirm-password.blade.php
├── forgot-password.blade.php
├── login.blade.php
├── register.blade.php
├── reset-password.blade.php
└── verify-email.blade.php
resources/views/
├── dashboard.blade.php ← Halaman setelah login
└── profile/
├── edit.blade.php ← Halaman edit profil
└── partials/
├── delete-user-form.blade.php
├── update-password-form.blade.php
└── update-profile-information-form.blade.php
app/Http/Controllers/
└── ProfileController.php ← Edit profil
routes/
├── auth.php ← Semua route autentikasi
└── web.php ← Dashboard route ditambahkan
tests/Feature/Auth/ ← Test untuk semua fitur auth
Memahami Route Autentikasi
Breeze menambahkan file routes/auth.php yang berisi semua route autentikasi, dan file ini di-include secara otomatis di routes/web.php. Mari pahami setiap route yang dihasilkan agar kamu tahu bagaimana alur autentikasi bekerja.
<?php
// routes/auth.php — dihasilkan otomatis oleh Breeze
use App\Http\Controllers\Auth\AuthenticatedSessionController;
use App\Http\Controllers\Auth\ConfirmablePasswordController;
use App\Http\Controllers\Auth\EmailVerificationNotificationController;
use App\Http\Controllers\Auth\EmailVerificationPromptController;
use App\Http\Controllers\Auth\NewPasswordController;
use App\Http\Controllers\Auth\PasswordController;
use App\Http\Controllers\Auth\PasswordResetLinkController;
use App\Http\Controllers\Auth\RegisteredUserController;
use Illuminate\Support\Facades\Route;
// ── GUEST ROUTES (hanya untuk yang BELUM login) ───────
Route::middleware('guest')->group(function () {
// Register
Route::get('register', [RegisteredUserController::class, 'create'])
->name('register');
Route::post('register', [RegisteredUserController::class, 'store']);
// Login
Route::get('login', [AuthenticatedSessionController::class, 'create'])
->name('login');
Route::post('login', [AuthenticatedSessionController::class, 'store']);
// Forgot Password
Route::get('forgot-password', [PasswordResetLinkController::class, 'create'])
->name('password.request');
Route::post('forgot-password', [PasswordResetLinkController::class, 'store'])
->name('password.email');
// Reset Password
Route::get('reset-password/{token}', [NewPasswordController::class, 'create'])
->name('password.reset');
Route::post('reset-password', [NewPasswordController::class, 'store'])
->name('password.store');
});
// ── AUTH ROUTES (hanya untuk yang SUDAH login) ────────
Route::middleware('auth')->group(function () {
// Email Verification
Route::get('verify-email', EmailVerificationPromptController::class)
->name('verification.notice');
Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
->middleware(['signed', 'throttle:6,1'])
->name('verification.verify');
Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
->middleware('throttle:6,1')
->name('verification.send');
// Confirm Password
Route::get('confirm-password', [ConfirmablePasswordController::class, 'show'])
->name('password.confirm');
Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']);
// Update Password
Route::put('password', [PasswordController::class, 'update'])
->name('password.update');
// Logout
Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])
->name('logout');
});
Memahami Cara Kerja Login
Mari bedah cara kerja proses login dari awal hingga akhir — dari pengguna mengklik tombol Login hingga diarahkan ke dashboard. Memahami alur ini akan membantumu mengkustomisasi perilaku login sesuai kebutuhan.
Request GET /login diterima router, diteruskan ke AuthenticatedSessionController@create yang mengembalikan view auth.login. Jika pengguna sudah login, middleware 'guest' otomatis redirect ke /dashboard.
Request POST /login diterima AuthenticatedSessionController@store. Request divalidasi menggunakan LoginRequest Form Request — termasuk pengecekan rate limiting (mencegah brute force: maks 5 percobaan per menit). Jika validasi gagal, redirect kembali dengan error.
LoginRequest memanggil Auth::attempt() dengan email dan password. Laravel otomatis mengambil user dari database berdasarkan email, lalu memverifikasi password menggunakan bcrypt comparison. Jika cocok, session dibuat dan user dianggap sudah login.
Setelah login berhasil, session di-regenerate untuk mencegah session fixation attack. User kemudian di-redirect ke intended URL (halaman yang dituju sebelum dipaksa login) atau ke /dashboard jika tidak ada intended URL.
<?php
// app/Http/Controllers/Auth/AuthenticatedSessionController.php
// Breeze menghasilkan ini — kita bedah untuk memahami cara kerjanya
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
class AuthenticatedSessionController extends Controller
{
// Tampilkan halaman login
public function create(): View
{
return view('auth.login');
}
// Proses form login
public function store(LoginRequest $request): RedirectResponse
{
// LoginRequest menangani:
// 1. Validasi email & password
// 2. Rate limiting (5 attempts/menit)
// 3. Auth::attempt() untuk verifikasi credentials
$request->authenticate();
// Regenerate session ID untuk mencegah session fixation
$request->session()->regenerate();
// Redirect ke URL yang dituju sebelum login
// atau ke /dashboard jika tidak ada
return redirect()->intended(route('dashboard', absolute: false));
}
// Proses logout
public function destroy(Request $request): RedirectResponse
{
Auth::logout();
// Invalidate session saat ini
$request->session()->invalidate();
// Generate CSRF token baru
$request->session()->regenerateToken();
return redirect('/');
}
}
<?php
// app/Http/Requests/Auth/LoginRequest.php
// Perhatikan bagaimana rate limiting diimplementasikan
namespace App\Http\Requests\Auth;
use Illuminate\Auth\Events\Lockout;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class LoginRequest extends FormRequest
{
public function rules(): array
{
return [
'email' => ['required', 'string', 'email'],
'password' => ['required', 'string'],
];
}
public function authenticate(): void
{
// Cek rate limit sebelum autentikasi
$this->ensureIsNotRateLimited();
// Coba autentikasi dengan credentials yang diberikan
if (!Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
// Tambah hit rate limiter jika gagal
RateLimiter::hit($this->throttleKey());
throw ValidationException::withMessages([
'email' => trans('auth.failed'),
]);
}
// Clear rate limiter jika berhasil
RateLimiter::clear($this->throttleKey());
}
protected function ensureIsNotRateLimited(): void
{
// Maks 5 percobaan per menit
if (!RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
return;
}
event(new Lockout($this));
$seconds = RateLimiter::availableIn($this->throttleKey());
throw ValidationException::withMessages([
'email' => trans('auth.throttle', [
'seconds' => $seconds,
'minutes' => ceil($seconds / 60),
]),
]);
}
protected function throttleKey(): string
{
// Key unik per email + IP address
return Str::transliterate(
Str::lower($this->string('email')) . '|' . $this->ip()
);
}
}
Middleware Auth: Melindungi Route
Setelah autentikasi terpasang, langkah selanjutnya adalah melindungi route-route yang hanya boleh diakses oleh pengguna yang sudah login. Laravel menyediakan middleware 'auth' untuk ini — dan Breeze sudah mengkonfigurasi semuanya sehingga kamu tinggal menggunakannya.
<?php
// routes/web.php — Melindungi route dengan middleware
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
use App\Http\Controllers\ProfileController;
// ── ROUTE PUBLIK (siapapun bisa akses) ───────────────
Route::get('/', fn() => view('welcome'))->name('home');
Route::get('/blog', [PostController::class, 'index'])->name('blog.index');
Route::get('/blog/{post:slug}', [PostController::class, 'show'])->name('blog.show');
// ── ROUTE YANG BUTUH LOGIN ─────────────────────────────
Route::middleware('auth')->group(function () {
Route::get('/dashboard', fn() => view('dashboard'))->name('dashboard');
// Profile routes (sudah ada dari Breeze)
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
// Post management
Route::resource('posts', PostController::class)->except(['index', 'show']);
});
// ── ROUTE YANG BUTUH LOGIN + VERIFIKASI EMAIL ──────────
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/premium', fn() => view('premium'))->name('premium');
});
// ── INCLUDE AUTH ROUTES DARI BREEZE ───────────────────
require __DIR__ . '/auth.php';
Menggunakan Auth Helper di Kode PHP
Laravel menyediakan berbagai cara untuk berinteraksi dengan sistem autentikasi di kode PHP — mengecek status login, mengambil data user yang sedang login, login secara manual, dan banyak lagi. Semua bisa diakses melalui facade Auth atau helper auth().
<?php
use Illuminate\Support\Facades\Auth;
// ── CEK STATUS LOGIN ───────────────────────────────────
Auth::check(); // true jika sudah login
Auth::guest(); // true jika belum login (kebalikan check())
auth()->check(); // Sama, menggunakan helper function
// ── AMBIL USER YANG SEDANG LOGIN ──────────────────────
$user = Auth::user(); // Instance User atau null
$user = auth()->user(); // Sama dengan di atas
$userId = Auth::id(); // Hanya ID, lebih efisien
$userId = auth()->id(); // Sama
// Akses properti user
echo auth()->user()->name;
echo auth()->user()->email;
echo auth()->user()->created_at->format('d M Y');
// ── LOGIN SECARA MANUAL ────────────────────────────────
// Berguna untuk login setelah register atau impersonation
$user = User::find(1);
Auth::login($user);
Auth::login($user, remember: true); // Dengan remember me
// Login dengan credentials
$credentials = ['email' => 'user@example.com', 'password' => 'password'];
if (Auth::attempt($credentials)) {
// Login berhasil
}
// Login hanya untuk request ini (tanpa session)
Auth::once($credentials);
// ── LOGOUT ─────────────────────────────────────────────
Auth::logout();
// ── DI CONTROLLER ─────────────────────────────────────
class PostController extends Controller
{
public function store(StorePostRequest $request)
{
$post = Post::create([
...$request->validated(),
'user_id' => auth()->id(), // ID user yang sedang login
]);
// Cek apakah user yang login adalah pemilik post
if (auth()->user()->cannot('update', $post)) {
abort(403);
}
}
}
// ── GUARD: Multi-auth (admin, user, dll) ──────────────
Auth::guard('admin')->check(); // Cek guard 'admin'
Auth::guard('api')->user(); // User dari guard 'api'
Menggunakan Auth di Blade Template
Blade menyediakan direktif khusus untuk kondisi autentikasi yang membuat template jauh lebih bersih dibanding menulis if auth()->check() secara manual. Direktif ini sudah kita singgung di bagian Blade, tapi mari kita lihat penerapannya yang lebih lengkap dalam konteks autentikasi.
{{-- ── DIREKTIF AUTH DI BLADE ─────────────────────── --}}
@auth
{{-- Konten ini HANYA muncul jika sudah login --}}
<div class="user-menu">
<span>Halo, {{ auth()->user()->name }}!</span>
<a href="{{ route('dashboard') }}">Dashboard</a>
<a href="{{ route('profile.edit') }}">Edit Profil</a>
<form action="{{ route('logout') }}" method="POST">
@csrf
<button type="submit">Logout</button>
</form>
</div>
@endauth
@guest
{{-- Konten ini HANYA muncul jika belum login --}}
<div class="auth-links">
<a href="{{ route('login') }}">Masuk</a>
<a href="{{ route('register') }}">Daftar</a>
</div>
@endguest
{{-- ── CEK KONDISI BERDASARKAN PROPERTI USER ──────── --}}
@if (auth()->check() && auth()->user()->is_admin)
<a href="{{ route('admin.dashboard') }}">Panel Admin</a>
@endif
{{-- ── TAMPILKAN TOMBOL EDIT HANYA UNTUK PEMILIK ──── --}}
@if (auth()->id() === $post->user_id)
<div class="post-actions">
<a href="{{ route('posts.edit', $post) }}">Edit</a>
<form action="{{ route('posts.destroy', $post) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit">Hapus</button>
</form>
</div>
@endif
{{-- ── NAVIGASI RESPONSIF DENGAN AUTH STATE ────────── --}}
<nav>
<a href="{{ route('home') }}">Beranda</a>
<a href="{{ route('blog.index') }}">Blog</a>
@auth
<a href="{{ route('dashboard') }}"
class="{{ request()->routeIs('dashboard') ? 'active' : '' }}">
Dashboard
</a>
{{-- Dropdown user --}}
<div class="dropdown">
<button>
@if (auth()->user()->avatar)
<img src="{{ Storage::url(auth()->user()->avatar) }}"
class="w-8 h-8 rounded-full">
@else
<div class="w-8 h-8 rounded-full bg-indigo-500 flex items-center justify-center text-white text-sm">
{{ strtoupper(substr(auth()->user()->name, 0, 1)) }}
</div>
@endif
{{ auth()->user()->name }}
</button>
<div class="dropdown-menu">
<a href="{{ route('profile.edit') }}">Edit Profil</a>
<form action="{{ route('logout') }}" method="POST">
@csrf
<button type="submit">Logout</button>
</form>
</div>
</div>
@endauth
@guest
<a href="{{ route('login') }}">Masuk</a>
<a href="{{ route('register') }}" class="btn-primary">Daftar Gratis</a>
@endguest
</nav>
Email Verification
Laravel Breeze sudah menyertakan fitur verifikasi email — memastikan email yang didaftarkan pengguna benar-benar miliknya dengan mengirim link verifikasi. Fitur ini tidak aktif secara default dan perlu dikonfigurasi jika dibutuhkan.
Tambahkan interface MustVerifyEmail ke model User. Dengan ini, Laravel akan mengirim email verifikasi saat user baru mendaftar dan middleware 'verified' bisa digunakan untuk melindungi route yang hanya boleh diakses user terverifikasi.
Untuk development, gunakan Mailtrap atau log driver agar email tidak benar-benar terkirim. Konfigurasi di file .env dan pastikan queue sudah berjalan jika menggunakan queue driver.
Tambahkan middleware 'verified' ke route yang hanya boleh diakses oleh user yang sudah memverifikasi email mereka. Jika user belum verifikasi, otomatis diarahkan ke halaman prompt verifikasi.
<?php
// app/Models/User.php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail; // ← Import interface
use Illuminate\Foundation\Auth\User as Authenticatable;
// Tambahkan implements MustVerifyEmail
class User extends Authenticatable implements MustVerifyEmail
{
// ... kode lainnya
}
# Konfigurasi mail di .env untuk development
# Opsi 1: Log (email ditulis ke storage/logs/laravel.log)
MAIL_MAILER=log
# Opsi 2: Mailtrap (email masuk ke inbox testing di mailtrap.io)
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_mailtrap_username
MAIL_PASSWORD=your_mailtrap_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="noreply@devpath.id"
MAIL_FROM_NAME="DevPath"
# Opsi 3: Resend, Mailgun, SES untuk production
# MAIL_MAILER=resend
# RESEND_API_KEY=re_xxxxxxxxxxxx
<?php
// routes/web.php — Gunakan middleware 'verified'
Route::middleware(['auth', 'verified'])->group(function () {
// Route ini hanya bisa diakses setelah verifikasi email
Route::get('/dashboard', fn() => view('dashboard'))->name('dashboard');
Route::resource('posts', PostController::class);
});
// ── CEK VERIFIKASI DI BLADE ────────────────────────────
// resources/views/layouts/app.blade.php
@auth
@if (!auth()->user()->hasVerifiedEmail())
<div class="bg-yellow-50 border-b border-yellow-200 py-2 px-4 text-sm text-center">
Email kamu belum diverifikasi.
<form action="{{ route('verification.send') }}" method="POST" class="inline">
@csrf
<button type="submit" class="underline font-medium">
Kirim ulang email verifikasi
</button>
</form>
</div>
@endif
@endauth
Mengkustomisasi Halaman Autentikasi
Salah satu keunggulan Breeze dibanding solusi autentikasi lain adalah semua kode yang dihasilkan berada di project kamu sendiri dan bisa dikustomisasi bebas. Tidak ada "black box" — kamu bisa mengubah tampilan, logika, dan perilaku sesuai kebutuhan.
{{-- resources/views/auth/login.blade.php --}}
{{-- Kustomisasi tampilan halaman login --}}
<x-guest-layout>
{{-- Session Status (untuk reset password berhasil) --}}
<x-auth-session-status class="mb-4" :status="session('status')" />
<div class="mb-8 text-center">
{{-- Ganti dengan logo aplikasimu --}}
<img src="{{ asset('images/logo.svg') }}" alt="DevPath" class="h-12 mx-auto mb-4">
<h1 class="text-2xl font-bold text-gray-900">Masuk ke Akun</h1>
<p class="text-gray-500 mt-1">Belum punya akun?
<a href="{{ route('register') }}" class="text-indigo-600 hover:underline">Daftar gratis</a>
</p>
</div>
<form method="POST" action="{{ route('login') }}">
@csrf
{{-- Email --}}
<div class="mb-4">
<x-input-label for="email" :value="__('Email')" />
<x-text-input
id="email"
class="block mt-1 w-full"
type="email"
name="email"
:value="old('email')"
required
autofocus
autocomplete="username"
placeholder="nama@email.com"
/>
<x-input-error :messages="$errors->get('email')" class="mt-2" />
</div>
{{-- Password --}}
<div class="mb-4">
<x-input-label for="password" :value="__('Password')" />
<x-text-input
id="password"
class="block mt-1 w-full"
type="password"
name="password"
required
autocomplete="current-password"
placeholder="••••••••"
/>
<x-input-error :messages="$errors->get('password')" class="mt-2" />
</div>
{{-- Remember Me + Forgot Password --}}
<div class="flex items-center justify-between mb-6">
<label class="flex items-center gap-2">
<input type="checkbox" name="remember">
<span class="text-sm text-gray-600">Ingat saya</span>
</label>
@if (Route::has('password.request'))
<a href="{{ route('password.request') }}"
class="text-sm text-indigo-600 hover:underline">
Lupa password?
</a>
@endif
</div>
<button type="submit"
class="w-full bg-indigo-600 text-white py-2.5 rounded-lg font-medium hover:bg-indigo-700 transition">
Masuk
</button>
{{-- Social Login (jika diperlukan) --}}
{{-- Bisa tambahkan Laravel Socialite di sini --}}
</form>
</x-guest-layout>
Mengkustomisasi Redirect Setelah Login dan Register
Secara default, Breeze mengarahkan pengguna ke /dashboard setelah login atau register. Kamu bisa mengubah perilaku ini untuk mengarahkan ke halaman yang berbeda berdasarkan role pengguna, atau menyimpan URL yang dituju sebelum login.
<?php
// Kustomisasi redirect setelah login
// app/Http/Controllers/Auth/AuthenticatedSessionController.php
public function store(LoginRequest $request): RedirectResponse
{
$request->authenticate();
$request->session()->regenerate();
$user = auth()->user();
// Redirect berbeda berdasarkan role
if ($user->is_admin) {
return redirect()->intended(route('admin.dashboard'));
}
if ($user->is_author) {
return redirect()->intended(route('author.dashboard'));
}
return redirect()->intended(route('dashboard'));
}
// ── REDIRECT SETELAH REGISTER ──────────────────────────
// app/Http/Controllers/Auth/RegisteredUserController.php
public function store(Request $request): RedirectResponse
{
// ... validasi dan create user ...
event(new Registered($user));
Auth::login($user);
// Redirect ke onboarding untuk user baru
return redirect(route('onboarding.welcome'));
// Atau ke dashboard biasa
// return redirect(route('dashboard'));
}
// ── KONSTANTA REDIRECT DI AppServiceProvider ──────────
// app/Providers/AppServiceProvider.php
use Illuminate\Http\RedirectResponse;
public function boot(): void
{
// Set home URL setelah login (untuk semua guard)
// Ini mempengaruhi redirect()->intended() jika tidak ada intended URL
}
// ── KONSTANTA DI RouteServiceProvider ─────────────────
// app/Providers/RouteServiceProvider.php
public const HOME = '/dashboard'; // Ubah ini untuk mengubah default redirect
Praktik: Menambahkan Fitur "Remember Last Visited" dan Role-Based Redirect
Mari implementasikan dua kustomisasi umum yang sering dibutuhkan aplikasi nyata — menyimpan halaman terakhir yang dikunjungi sebelum login agar pengguna diarahkan ke sana setelah berhasil masuk, dan redirect berbeda berdasarkan role pengguna.
<?php
// app/Http/Middleware/RedirectIfAuthenticated.php
// Kustomisasi redirect untuk user yang sudah login tapi akses halaman guest
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class RedirectIfAuthenticated
{
public function handle(Request $request, Closure $next, string ...$guards): Response
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
$user = Auth::guard($guard)->user();
// Redirect berdasarkan role
return match (true) {
$user->is_admin => redirect()->route('admin.dashboard'),
$user->is_author => redirect()->route('author.dashboard'),
default => redirect(RouteServiceProvider::HOME),
};
}
}
return $next($request);
}
}
// ── SIMPAN INTENDED URL SECARA MANUAL ─────────────────
// Berguna jika ada link "Login untuk komentar" di halaman post
// Di blade, tambahkan intended URL ke link login:
// <a href="{{ route('login', ['intended' => url()->current()]) }}">
// Login untuk berkomentar
// </a>
// Di AuthenticatedSessionController@create:
public function create(Request $request): View
{
// Simpan intended URL ke session jika ada di query string
if ($request->has('intended')) {
session(['url.intended' => $request->intended]);
}
return view('auth.login');
}
// ── MODEL USER DENGAN ROLE HELPER ─────────────────────
// app/Models/User.php
class User extends Authenticatable
{
protected $casts = [
'is_admin' => 'boolean',
'is_author' => 'boolean',
'email_verified_at' => 'datetime',
];
public function isAdmin(): bool
{
return $this->is_admin === true;
}
public function isAuthor(): bool
{
return $this->is_author === true || $this->is_admin === true;
}
// Cek role secara dinamis
public function hasRole(string $role): bool
{
return match ($role) {
'admin' => $this->is_admin,
'author' => $this->is_author || $this->is_admin,
default => false,
};
}
// Dashboard URL berdasarkan role
public function dashboardUrl(): string
{
if ($this->is_admin) return route('admin.dashboard');
if ($this->is_author) return route('author.dashboard');
return route('dashboard');
}
}
💡 Untuk sistem role yang lebih kompleks dengan puluhan permission, pertimbangkan menggunakan package Spatie Laravel Permission (spatie/laravel-permission). Package ini menyediakan sistem role dan permission yang sangat lengkap dengan database-driven approach, dan sangat populer di ekosistem Laravel Indonesia. Namun untuk aplikasi sederhana dengan hanya 2-3 role, kolom boolean di tabel users seperti is_admin dan is_author sudah lebih dari cukup.
Langkah Selanjutnya
Luar biasa — kamu sudah menguasai Authentication dengan Laravel Breeze secara menyeluruh! Mulai dari instalasi, memahami semua file yang dihasilkan, cara kerja proses login dengan rate limiting, middleware auth untuk melindungi route, penggunaan Auth helper di PHP dan Blade, email verification, hingga berbagai kustomisasi yang sering dibutuhkan aplikasi nyata. Di bagian kesepuluh seri ini, kita akan membahas Middleware dan Authorization — cara yang lebih terstruktur untuk mengontrol akses ke fitur dan resource dalam aplikasi Laravel menggunakan Gates dan Policies.
🚀 Sebelum lanjut ke Bagian 10, pastikan kamu sudah berlatih: (1) menginstal Breeze dan menjelajahi semua halaman auth yang dihasilkan, (2) melindungi route dengan middleware 'auth' dan 'verified', (3) menggunakan auth()->user() dan direktif @auth/@guest di berbagai tempat di aplikasimu, (4) mengkustomisasi tampilan halaman login sesuai desain aplikasimu, dan (5) menguji alur forgot password dari awal hingga password berhasil direset. Sistem autentikasi yang berfungsi dengan baik adalah fondasi kepercayaan pengguna terhadap aplikasimu.