Loading...
Halo teman-teman developer! ๐
Kalau kamu sedang bikin aplikasi Laravel 12 dan ingin memisahkan login antara Admin dan User biasa, berarti kamu butuh yang namanya Multi Auth.
Multi Auth memungkinkan dua sistem login yang berbeda dalam satu aplikasi — misalnya, admin punya halaman login sendiri di /admin/login, sementara user biasa tetap login di /login.
Laravel 12 sudah sangat fleksibel untuk ini, apalagi kalau pakai Laravel Breeze untuk setup autentikasi dasarnya. Kali ini kita akan bahas dari awal banget — mulai dari membuat project, setup database, model Admin, sampai sistem login lengkap dengan middleware dan seeder.
Buka terminal dan jalankan perintah berikut:
composer create-project laravel/laravel multi-auth-app
cd multi-auth-app
Pastikan project berjalan lancar:
php artisan serve
Buka di browser: http://localhost:8000 — kalau muncul halaman Laravel, berarti sukses ๐
Buka file .env dan ubah pengaturan database-nya seperti berikut:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=multi_auth
DB_USERNAME=root
DB_PASSWORD=
Buat database di phpMyAdmin atau terminal:
CREATE DATABASE multi_auth;
composer require laravel/breeze --dev
php artisan breeze:install blade
npm install && npm run dev
php artisan migrate
Setelah ini, kamu sudah bisa login dan register user biasa di /login dan /register.
php artisan make:model Admin -m
Edit migration di database/migrations/<tanggal>_create_admins_table.php:
Schema::create('admins', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Lalu isi model app/Models/Admin.php dengan kode berikut:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class Admin extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
}
Setelah itu, jalankan migrasi:
php artisan migrate
config/auth.phpTambahkan konfigurasi untuk guard dan provider admin:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],
php artisan make:controller Admin/AuthController
Isi app/Http/Controllers/Admin/AuthController.php:
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
public function showLoginForm()
{
// Jika admin sudah login, arahkan langsung ke dashboard
if (Auth::guard('admin')->check()) {
return redirect()->route('admin.dashboard');
}
return view('admin.login');
}
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::guard('admin')->attempt($credentials)) {
return redirect()->intended('/admin/dashboard');
}
return back()->withErrors(['email' => 'Email atau password salah']);
}
public function logout()
{
Auth::guard('admin')->logout();
return redirect('/admin/login');
}
}
php artisan make:middleware RedirectIfNotAdmin
Edit app/Http/Middleware/RedirectIfNotAdmin.php:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfNotAdmin
{
public function handle($request, Closure $next)
{
if (!Auth::guard('admin')->check()) {
return redirect()->route('admin.login');
}
return $next($request);
}
}
use App\Http\Controllers\Admin\AuthController;
use App\Http\Middleware\RedirectIfNotAdmin;
Route::prefix('admin')->name('admin.')->group(function () {
// Login & Logout
Route::get('/login', [AuthController::class, 'showLoginForm'])->name('login');
Route::post('/login', [AuthController::class, 'login']);
Route::post('/logout', [AuthController::class, 'logout'])->name('logout');
// Dashboard dilindungi middleware
Route::get('/dashboard', function () {
return view('admin.dashboard');
})->middleware(RedirectIfNotAdmin::class)->name('dashboard');
});
Buat file resources/views/admin/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>Login Admin</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Poppins', sans-serif;
}
</style>
</head>
<body class="bg-gradient-to-br from-blue-50 via-white to-purple-50 min-h-screen flex items-center justify-center p-4">
<div class="bg-white w-full max-w-md p-8 md:p-10 rounded-2xl shadow-2xl transition-all duration-300">
<div class="flex justify-center mb-4">
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 text-blue-600" fill="none" viewBox="0 0 24 24"
stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round"
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
</div>
<h2 class="text-3xl font-bold text-gray-900 text-center mb-2">Login Admin</h2>
<p class="text-gray-500 text-center mb-8">Selamat datang kembali! Silakan masuk.</p>
@if ($errors->any())
<div class="bg-red-50 border border-red-300 text-red-800 rounded-xl p-3 text-sm mb-6" role="alert">
<p>{{ $errors->first() }}</p>
</div>
@endif
<form method="POST" action="{{ route('admin.login') }}" class="space-y-5">
@csrf
<div>
<label for="email" class="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input type="email" name="email" id="email" placeholder="admin@email.com" required
autocomplete="email"
class="w-full px-4 py-3 border border-gray-300 rounded-xl shadow-sm bg-gray-50
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent
transition-all"
value="{{ old('email') }}">
</div>
<div>
<label for="password" class="block text-sm font-medium text-gray-700 mb-1">Password</label>
<input type="password" name="password" id="password" placeholder="••••••••" required
autocomplete="current-password"
class="w-full px-4 py-3 border border-gray-300 rounded-xl shadow-sm bg-gray-50
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent
transition-all">
</div>
<div>
<button type="submit"
class="w-full bg-blue-600 text-white py-3 px-4 rounded-xl font-bold shadow-lg
hover:bg-blue-700
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
transform hover:-translate-y-0.5 transition-all duration-300 ease-in-out">
Login
</button>
</div>
</form>
</div>
</body>
</html>
Buat file resources/views/admin/dashboard.blade.php
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Dashboard</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Poppins', sans-serif;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen">
<nav class="bg-white shadow-md">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex items-center">
<span class="text-2xl font-bold text-blue-600">Admin Panel</span>
</div>
<div class="flex items-center">
<a href="{{ route('admin.logout') }}"
onclick="event.preventDefault(); document.getElementById('logout-form').submit();"
class="bg-red-500 text-white px-4 py-2 rounded-lg text-sm font-medium
hover:bg-red-600 transition-colors duration-300
focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2">
Logout
</a>
<form id="logout-form" action="{{ route('admin.logout') }}" method="POST" class="hidden">
@csrf
</form>
</div>
</div>
</div>
</nav>
<main>
<div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:px-8">
<div class="bg-white rounded-2xl shadow-xl p-8 md:p-12 text-center">
<div class="flex justify-center mb-4">
<svg xmlns="http://www.w3.org/2000/svg" class="h-20 w-20 text-green-500" fill="none"
viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<h1 class="text-4xl font-bold text-gray-900 mb-2">
Selamat datang, Admin!
</h1>
<p class="text-lg text-gray-600">
Anda telah berhasil login ke panel admin.
</p>
</div>
</div>
</main>
</body>
</html>
php artisan make:seeder UserAndAdminSeeder
Edit database/seeders/UserAndAdminSeeder.php:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
use App\Models\User;
use App\Models\Admin;
class UserAndAdminSeeder extends Seeder
{
public function run(): void
{
// User biasa
User::updateOrCreate(
['email' => 'user@example.com'],
[
'name' => 'User Biasa',
'password' => Hash::make('password'),
]
);
// Admin
Admin::updateOrCreate(
['email' => 'admin@example.com'],
[
'name' => 'Admin Super',
'password' => Hash::make('password'),
]
);
$this->command->info('โ
User dan Admin berhasil dibuat!');
}
}
Edit database/seeders/DatabaseSeeder.php agar seeder otomatis dijalankan:
public function run(): void
{
$this->call(UserAndAdminSeeder::class);
}
Jalankan seeder:
php artisan db:seed
Gunakan akun berikut untuk mencoba:
| Role | Password | URL Login | |
|---|---|---|---|
| User | user@example.com | password | /login |
| Admin | admin@example.com | password | /admin/login |
Sekarang kamu punya dua sistem login berbeda dengan session terpisah:
| Role | Guard | Model | Login Path |
|---|---|---|---|
| User | web | App\Models\User | /login |
| Admin | admin | App\Models\Admin | /admin/login |
Dengan langkah-langkah di atas, kamu sudah punya sistem Multi Auth Laravel 12 yang lengkap:
Sekarang kamu bisa lanjut menambahkan fitur role-based access, CRUD untuk admin, dan dashboard keren sesuai kebutuhanmu. Selamat ngoding! ๐๐ฅ