Materi Lengkap: Implementasi Login Manual dengan Laravel (Session + Middleware Auth)
1. Tujuan Pembelajaran
Setelah menyelesaikan materi ini, peserta diharapkan mampu:
- Memahami konsep autentikasi berbasis session di Laravel.
- Membuat sistem login dan logout dengan controller khusus.
- Merancang routing group yang dilindungi middleware.
- Menerapkan middleware
authuntuk membatasi akses ke halaman tertentu. - Menghubungkan sistem login dengan fitur yang sudah ada (contoh: manajemen produk).
2. Gambaran Umum Alur Autentikasi
Sebelum terjun ke kode, mari kita pahami alur yang akan kita bangun. Ini adalah "cerita" dari sistem login kita:
- Pengguna yang belum login mencoba mengakses halaman produk (
/products). - Middleware
authakan menangkap permintaan itu, melihat bahwa tidak ada session login, lalu mengalihkan (redirect) pengguna ke halaman login (/login). - Di halaman login, pengguna mengisi email dan password, lalu menekan tombol submit.
- Data kredensial (email & password) dikirim ke server untuk divalidasi dan dicocokkan dengan data di tabel
users. - Jika cocok (authentication successful), Laravel akan membuat session login untuk pengguna tersebut. Pengguna kemudian diarahkan ke halaman yang awalnya ingin dia tuju (
/products). - Kini, ketika pengguna mengakses
/productslagi, middlewareauthakan memeriksa session yang valid dan mengizinkan akses. - Saat pengguna memilih logout, session tersebut akan dihancurkan, dan pengguna dikembalikan ke halaman login.
Dengan memahami cerita ini, kode yang kita tulis nanti akan lebih bermakna.
3. Persiapan: Database dan Tabel Users
Laravel sudah menyediakan migration untuk tabel users secara default. Pastikan Anda telah menjalankan migrasi untuk membuat tabelnya di database.
php artisan migrate
Tabel users ini memiliki kolom-kolom penting seperti id, name, email, password (yang disimpan dalam bentuk terenkripsi/hash), dan remember_token. Kita akan menggunakan email dan password untuk proses login.
4. Membangun Sistem Login: Controller dan View
Langkah pertama adalah membuat Controller yang menangani logika login dan logout. Kita akan beri nama AuthController.
php artisan make:controller AuthController
File: app/Http/Controllers/AuthController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
/**
* Menampilkan halaman form login.
*/
public function showLoginForm()
{
// Mengembalikan view 'auth.login'
return view('auth.login');
}
/**
* Memproses data login yang dikirim dari form.
*/
public function login(Request $request)
{
// 1. Validasi input form
$credentials = $request->validate([
'email' => 'required|email',
'password' => 'required|min:6',
]);
// 2. Attempt Login: Mencocokkan kredensial dengan database
if (Auth::attempt($credentials)) {
// 3. Regenerasi Session (untuk keamanan)
$request->session()->regenerate();
// 4. Redirect ke URL yang dimaksud sebelumnya, atau ke halaman default ('/products')
return redirect()->intended('/products');
}
// 5. Jika attempt gagal, kembali ke halaman login dengan pesan error
return back()->withErrors([
'email' => 'Email atau password yang dimasukkan salah.',
]);
}
/**
* Memproses permintaan logout.
*/
public function logout(Request $request)
{
// 1. Logout user (menghapus session auth)
Auth::logout();
// 2. Invalidasi session saat ini
$request->session()->invalidate();
// 3. Regenerasi CSRF token (untuk keamanan)
$request->session()->regenerateToken();
// 4. Redirect ke halaman login
return redirect('/login');
}
}
Penjelasan Kode Controller:
- Fungsi
attempt()dari FacadeAuthadalah inti dari login. Ia akan mengenkripsi password inputan, mencocokkannya dengan hash di database, dan secara otomatis menginisiasi session jika berhasil. redirect()->intended()adalah fitur cerdas Laravel. Ia akan mengingat URL yang ingin diakses pengguna sebelum di-intercept middleware, sehingga setelah login, pengguna langsung dibawa ke tujuan awalnya.- Proses logout harus menghancurkan session sepenuhnya (
invalidate()) dan membuat token baru (regenerateToken()) untuk mencegah serangan session fixation.
Selanjutnya, kita buat view untuk halaman login. Kita akan menggunakan Bootstrap untuk styling yang cepat dan rapi.
File: resources/views/auth/login.blade.php
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Halaman Login</title>
<!-- Menghubungkan CSS Bootstrap 5 -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light d-flex align-items-center" style="min-height: 100vh;">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-5">
<div class="card shadow">
<div class="card-header bg-primary text-white text-center py-3">
<h4>Login ke Sistem</h4>
</div>
<div class="card-body p-4">
<!-- Menampilkan pesan error jika validasi/login gagal -->
@if($errors->any())
<div class="alert alert-danger alert-dismissible fade show" role="alert">
{{ $errors->first() }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
@endif
<form action="{{ route('login') }}" method="POST">
@csrf <!-- Token CSRF Wajib untuk keamanan form Laravel -->
<div class="mb-3">
<label for="email" class="form-label">Alamat Email</label>
<input type="email"
class="form-control @error('email') is-invalid @enderror"
id="email"
name="email"
value="{{ old('email') }}"
placeholder="[email protected]"
required>
</div>
<div class="mb-4">
<label for="password" class="form-label">Password</label>
<input type="password"
class="form-control @error('password') is-invalid @enderror"
id="password"
name="password"
placeholder="Masukkan password"
required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg">Masuk</button>
</div>
</form>
</div>
<div class="card-footer text-center text-muted py-3">
<small>Demo Sistem Login Laravel</small>
</div>
</div>
</div>
</div>
</div>
<!-- Menghubungkan JavaScript Bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
5. Menghubungkan Semuanya: Routing
Routing adalah penghubung antara URL, Controller, dan Middleware. Kita akan atur rute untuk publik (login) dan privat (yang dilindungi).
File: routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
use App\Http\Controllers\ProductController; // Asumsi kita punya controller untuk produk
// --- ROUTE PUBLIK YANG SUDAH ADA SEBELUMNYA (TANPA MIDDLEWARE) ---
Route::get('/', [HomeController::class, 'home']);
Route::get('/about', [HomeController::class, 'about']);
Route::get('/contact', [HomeController::class, 'contact']);
Route::get('/tentang-aplikasi', [HomeController::class, 'tentang_aplikasi']);
// --- ROUTE PUBLIK (TANPA MIDDLEWARE) ---
// Hanya pengguna belum login yang bisa akses
Route::get('/login', [AuthController::class, 'showLoginForm'])->name('login');
Route::post('/login', [AuthController::class, 'login']);
Route::post('/logout', [AuthController::class, 'logout'])->name('logout');
// --- ROUTE PRIVAT (DILINDUNGI MIDDLEWARE 'auth') ---
// Hanya pengguna yang sudah login yang bisa akses
Route::middleware(['auth'])->group(function () {
// Semua route di dalam grup ini otomatis terlindungi
// Contoh: Route untuk manajemen produk
Route::get('/products', [ProductController::class, 'index'])->name('products.index');
Route::get('/products/create', [ProductController::class, 'create'])->name('products.create');
Route::post('/products', [ProductController::class, 'store'])->name('products.store');
Route::get('/products/{product}/edit', [ProductController::class, 'edit'])->name('products.edit');
Route::put('/products/{product}', [ProductController::class, 'update'])->name('products.update');
Route::delete('/products/{product}', [ProductController::class, 'destroy'])->name('products.destroy');
// Contoh route lain yang perlu login
Route::get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
});
Mengapa route login dan logout berada di luar grup middleware auth?
Karena jika mereka dilindungi, pengguna yang belum login tidak akan bisa mengakses halaman login sama sekali—dan akan terjebak dalam loop redirect.
6. Middleware Auth: Sang Penjaga Gerbang
Source: buildwithangga.com
Ini adalah bagian kunci dari materi kita. Middleware auth adalah penjaga yang berdiri di depan route privat kita. Cara kerjanya sederhana namun kuat:
- Intercept: Setiap kali ada request masuk ke route di dalam grupnya, middleware
authdijalankan terlebih dahulu. - Cek Session: Middleware ini memeriksa, "Apakah request ini memiliki session login yang valid?"
- Keputusan:
- Jika YA: Request diteruskan ke controller tujuan (misal,
ProductController). - Jika TIDAK: Request dibelokkan (
redirect) ke route bernama'login'. Laravel secara otomatis menambahkan parameter?next=yang berisi URL yang gagal diakses.
- Jika YA: Request diteruskan ke controller tujuan (misal,
Kita tidak perlu menulis kode middleware ini karena sudah disediakan oleh Laravel. Kita hanya perlu menerapkannya dengan benar pada route, seperti yang telah dilakukan di atas.
7. Menyiapkan Data Pengguna (Seeder)
Untuk keperluan pengembangan dan testing, kita perlu membuat data user contoh. Kita buat sebuah Seeder.
php artisan make:seeder UserSeeder
File: database/seeders/UserSeeder.php
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class UserSeeder extends Seeder
{
public function run()
{
// Hapus data lama jika ada (optional)
User::truncate();
// Buat user admin contoh
User::create([
'name' => 'Administrator',
'email' => '[email protected]',
'password' => Hash::make('password123'), // Password di-hash
]);
// Bisa ditambahkan user lain di sini
User::create([
'name' => 'User Biasa',
'email' => '[email protected]',
'password' => Hash::make('rahasia456'),
]);
$this->command->info('Sample user created successfully!');
}
}
Jalankan seeder ini untuk menambahkan user ke database:
php artisan db:seed --class=UserSeeder
Sekarang Anda bisa login dengan email [email protected] dan password password123.
Oke, kita integrasikan materi Menu Dinamis Berdasarkan Status Login ke dalam materi yang sama. Saya akan tambahkan bagian ini setelah middleware auth, dengan penjelasan yang ringkas namun komprehensif.
Lanjutan: Integrasi Menu Navbar Dinamis
8. Implementasi Menu Dinamis Berdasarkan Status Login
Setelah sistem login dan middleware berjalan, langkah logis berikutnya adalah menyesuaikan tampilan navbar berdasarkan apakah pengguna sudah login atau belum. Ini penting untuk UX yang baik dan keamanan.
Kita akan modifikasi layout utama (biasanya resources/views/layouts/main.blade.php)
Harap di perhatikan, untuk nama file layouts bisa saja berbeda beda tergantung pada project masing masing!.
untuk memiliki dua kondisi:
- Menu untuk Pengguna Belum Login: Menampilkan link Login.
- Menu untuk Pengguna Sudah Login: Menampilkan link Dashboard/Produk, nama user, dan tombol Logout.
File: resources/views/layouts/main.blade.php (Revisi)
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@yield('title', 'CRUD Produk')</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a href="/" class="navbar-brand">CRUD Produk</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<!-- Menu Kiri (Selalu Tampil) -->
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a href="/" class="nav-link {{ request()->is('/') ? 'active' : '' }}">Home</a>
</li>
<li class="nav-item">
<a href="/about" class="nav-link {{ request()->is('about') ? 'active' : '' }}">About</a>
</li>
</ul>
<!-- Menu Kanan (Kondisional) -->
<ul class="navbar-nav">
<!-- Menu yang hanya tampil jika user SUDAH login -->
@auth
<!-- Menu untuk user yang SUDAH login -->
<li class="nav-item">
<a href="{{ url('/dashboard') }}"
class="nav-link {{ request()->is('dashboard') ? 'active' : '' }}">
Dashboard
</a>
</li>
<li class="nav-item">
<a href="{{ route('products.index') }}"
class="nav-link {{ request()->is('products*') ? 'active' : '' }}">
Produk
</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
{{ Auth::user()->name }} <!-- Menampilkan nama user -->
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="{{ url('/dashboard') }}">Dashboard</a></li>
<li>
<hr class="dropdown-divider">
</li>
<!-- Form Logout -->
<li>
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="dropdown-item text-danger">Logout</button>
</form>
</li>
</ul>
</li>
@else
<!-- Menu untuk user yang BELUM login -->
<li class="nav-item">
<a href="{{ route('login') }}" class="nav-link">Login</a>
</li>
@endauth
</ul>
</div>
</div>
</nav>
<!-- Konten Utama -->
<div class="container mt-4">
@yield('content')
</div>
<!-- Script Bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<!-- Script Tambahan per Halaman -->
@stack('scripts')
</body>
</html>
Penjelasan Kode Navbar Dinamis:
-
Blade Directives
@authdan@endauth: Direktif ini adalah cara paling sederhana untuk mengecek status login.Kode di dalamnya hanya akan ditampilkan jika user sudah terautentikasi. -
Blade Directives
@guestdan@endguest: Alternatif untuk@auth, khusus untuk pengguna yang belum login. Dalam kode di atas, saya menggunakan@elsedari@authuntuk efisiensi. -
Menampilkan Data User:
{{ Auth::user()->name }}menampilkan nama user yang sedang login.Auth::user()mengembalikan object model User, jadi kita bisa akses semua kolom sepertiemail,id, dll. -
Form Logout di Dropdown: Logout harus menggunakan form POST karena tindakan ini merubah state aplikasi. Form kecil ini mengirimkan request ke route
logoutdengan token CSRF. -
Highlight Menu Aktif:
{{ request()->is('products*') ? 'active' : '' }}menambahkan classactivejika URL saat ini berada di pathproductsatau turunannya. Memberikan visual feedback yang baik untuk user.
Adaptasi View Lainnya:
Setiap view yang menggunakan layout ini (misal products/index.blade.php), cukup diawali dengan:
@extends('layouts.app')
@section('title', 'Daftar Produk')
@section('content')
<!-- Konten halaman produk di sini -->
@endsection
Rute Dashboard:
Pastikan Anda menambahkan rute untuk dashboard di dalam grup middleware auth:
// Di dalam Route::middleware(['auth'])->group(function () { ... });
Route::get('/dashboard', function () {
return view('dashboard'); // Buat file resources/views/dashboard.blade.php
})->name('dashboard');
Keuntungan Implementasi Ini:
- User Experience Lebih Baik: Pengguna langsung tahu status login mereka.
- Keamanan: Menu terproteksi tidak ditampilkan ke pengguna anonim.
- Konsistensi: Semua halaman menggunakan navbar yang sama dengan logika kondisional.
- Mudah Dikembangkan: Cukup bungkus menu dengan
@auth/@guestuntuk kontrol tampilan.
Testing Navbar Dinamis:
- Akses homepage tanpa login: Hanya tampil menu Home, About, dan Login.
- Login dengan akun admin: Menu Produk muncul, nama user tampil di dropdown dengan opsi Logout.
- Klik Logout: Kembali ke state pertama.
9. Kesimpulan
Dengan integrasi navbar dinamis ini, sistem login kita sudah komplit dari backend hingga frontend. Pengguna mendapatkan pengalaman yang mulus dan aman.
Rangkuman yang telah kita bangun:
- ✅ Sistem Login Manual dengan Controller dan Session
- ✅ Middleware Auth sebagai Penjaga Route
- ✅ Navbar Dinamis Berdasarkan Status Login
- ✅ Form Logout yang Aman
Ringkasan Struktur Folder Proyek Laravel 12 (Setelah Implementasi Login + Navbar)
📁 laravel-12-project/
│
├── 📁 app/
│ ├── 📁 Http/
│ │ └── 📁 Controllers/
│ │ ├── AuthController.php # Controller login/logout (BARU)
│ │ ├── ProductController.php # Controller produk (sudah ada)
│ │ └── Controller.php
│ │
│ ├── 📁 Models/
│ │ ├── User.php # Model User (default)
│ │ └── Product.php # Model Produk (jika ada)
│ │
│ └── ...
│
├── 📁 bootstrap/
│ └── app.php # Tempat definisi middleware
│
├── 📁 database/
│ ├── 📁 migrations/
│ │ ├── 2014_10_12_000000_create_users_table.php
│ │ ├── ..._create_products_table.php # Migration produk (jika ada)
│ │ └── ...
│ │
│ ├── 📁 seeders/
│ │ ├── DatabaseSeeder.php
│ │ └── UserSeeder.php # Seeder user (BARU)
│ │
│ └── ...
│
├── 📁 resources/
│ ├── 📁 views/
│ │ ├── 📁 layouts/
│ │ │ └── app.blade.php # Layout utama (SUDAH DIUPDATE)
│ │ │
│ │ ├── 📁 auth/ # Folder baru untuk auth views
│ │ │ └── login.blade.php # View login (BARU)
│ │ │
│ │ ├── 📁 products/ # View produk (sudah ada)
│ │ │ ├── index.blade.php
│ │ │ ├── create.blade.php
│ │ │ └── ...
│ │ │
│ │ └── dashboard.blade.php # View dashboard (BARU, opsional)
│ │
│ └── ...
│
├── 📁 routes/
│ └── web.php # SUDAH DIUPDATE dengan routing auth
│
├── .env
├── composer.json
└── ...

