Membuat Login Multi-Role dengan PHP untuk Pemula
Login multi-role dengan PHP berarti satu sistem login bisa membedakan hak akses user, misalnya admin, editor, dan user. Jawaban cepatnya: simpan role di tabel users, hash password dengan password_hash(), verifikasi login dengan password_verify(), lalu lindungi setiap halaman memakai helper seperti requireRole('admin').
Halaman ini cocok kalau kamu sudah memahami Session dan Autentikasi, Keamanan Password, dan Authentication vs Authorization. Kita akan membuat versi sederhana yang mudah dibaca pemula, tetapi tetap memakai prinsip penting: password tidak disimpan polos, akses tidak hanya disembunyikan dari menu, dan semua halaman sensitif harus dicek di server.
Gambaran Fitur
Project kecil ini punya tiga role:
Alur aplikasinya:
- User membuka
login.php.
- PHP mencari username di database.
- Password dicek dengan
password_verify().
- Jika benar, session menyimpan
user_id, username, dan role.
- Halaman tertentu memanggil
requireRole() untuk membatasi akses.
Struktur Folder
Gunakan struktur sederhana berikut:
login-multi-role/
├── config/
│ ├── database.php
│ └── auth.php
├── admin/
│ └── index.php
├── editor/
│ └── index.php
├── user/
│ └── index.php
├── login.php
├── logout.php
└── seed-user.php
Untuk latihan, seed-user.php dipakai sekali untuk membuat akun awal. Di project production, pembuatan user sebaiknya lewat halaman admin atau proses registrasi yang terkontrol.
Membuat Tabel Users
Buat database dan tabel:
CREATE DATABASE belajar_login_role;
USE belajar_login_role;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
nama VARCHAR(100) NOT NULL,
role ENUM('admin', 'editor', 'user') NOT NULL DEFAULT 'user',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Kolom role menentukan hak akses. Kita memakai ENUM agar nilai role terbatas pada daftar yang jelas.
Koneksi Database
Isi config/database.php:
<?php
declare(strict_types=1);
$host = '127.0.0.1';
$db = 'belajar_login_role';
$user = 'root';
$pass = '';
$pdo = new PDO(
"mysql:host={$host};dbname={$db};charset=utf8mb4",
$user,
$pass,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
Kalau koneksi database gagal, baca juga Koneksi Database dan Cara Mengatasi SQLSTATE Error di PHP PDO.
Membuat User Awal
Isi seed-user.php:
<?php
declare(strict_types=1);
require __DIR__ . '/config/database.php';
$users = [
['admin', 'admin123', 'Administrator', 'admin'],
['editor', 'editor123', 'Editor Konten', 'editor'],
['budi', 'user123', 'Budi Santoso', 'user'],
];
$stmt = $pdo->prepare("
INSERT INTO users (username, password, nama, role)
VALUES (?, ?, ?, ?)
");
foreach ($users as [$username, $password, $nama, $role]) {
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt->execute([$username, $hash, $nama, $role]);
}
echo 'User awal berhasil dibuat.';
Jalankan sekali dari browser atau terminal, lalu hapus file ini setelah selesai agar akun contoh tidak dibuat berulang-ulang.
Membuat Helper Auth
Isi config/auth.php:
<?php
declare(strict_types=1);
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
function isLogin(): bool
{
return isset($_SESSION['user_id']);
}
function currentUser(): array
{
return [
'id' => $_SESSION['user_id'] ?? null,
'username' => $_SESSION['username'] ?? null,
'nama' => $_SESSION['nama'] ?? null,
'role' => $_SESSION['role'] ?? null,
];
}
function requireLogin(): void
{
if (!isLogin()) {
header('Location: /login.php');
exit;
}
}
function requireRole(string ...$roles): void
{
requireLogin();
$userRole = $_SESSION['role'] ?? '';
if (!in_array($userRole, $roles, true)) {
http_response_code(403);
echo '403 - Akses ditolak.';
exit;
}
}
requireRole() menerima lebih dari satu role. Misalnya halaman konten boleh diakses admin dan editor.
Membuat Halaman Login
Isi login.php:
<?php
declare(strict_types=1);
require __DIR__ . '/config/database.php';
require __DIR__ . '/config/auth.php';
if (isLogin()) {
header('Location: /user/index.php');
exit;
}
$error = '';
$username = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = ? LIMIT 1');
$stmt->execute([$username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['nama'] = $user['nama'];
$_SESSION['role'] = $user['role'];
if ($user['role'] === 'admin') {
header('Location: /admin/index.php');
} elseif ($user['role'] === 'editor') {
header('Location: /editor/index.php');
} else {
header('Location: /user/index.php');
}
exit;
}
$error = 'Username atau password salah.';
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Login Multi-Role PHP</title>
</head>
<body>
<h1>Login Multi-Role</h1>
<?php if ($error !== ''): ?>
<p style="color: red;"><?= htmlspecialchars($error) ?></p>
<?php endif; ?>
<form method="POST">
<label>
Username
<input type="text" name="username" value="<?= htmlspecialchars($username) ?>" required>
</label>
<label>
Password
<input type="password" name="password" required>
</label>
<button type="submit">Masuk</button>
</form>
</body>
</html>
Perhatikan dua detail penting:
session_regenerate_id(true) dijalankan setelah login berhasil.
- Pesan error dibuat umum: jangan beri tahu apakah username atau password yang salah.
Melindungi Halaman Berdasarkan Role
Contoh halaman admin, admin/index.php:
<?php
require __DIR__ . '/../config/auth.php';
requireRole('admin');
$user = currentUser();
?>
<h1>Dashboard Admin</h1>
<p>Halo, <?= htmlspecialchars($user['nama']) ?>.</p>
<p>Halaman ini hanya untuk role admin.</p>
<a href="/logout.php">Logout</a>
Contoh halaman editor, editor/index.php:
<?php
require __DIR__ . '/../config/auth.php';
requireRole('admin', 'editor');
?>
<h1>Dashboard Editor</h1>
<p>Admin dan editor boleh membuka halaman ini.</p>
Contoh halaman user biasa, user/index.php:
<?php
require __DIR__ . '/../config/auth.php';
requireLogin();
$user = currentUser();
?>
<h1>Dashboard User</h1>
<p>Role kamu: <?= htmlspecialchars($user['role']) ?></p>
Logout
Isi logout.php:
<?php
session_start();
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain']);
}
session_destroy();
header('Location: /login.php');
exit;
Kesalahan yang Sering Terjadi
Menu yang disembunyikan bukan keamanan. User tetap bisa mengetik URL manual. Setiap file admin harus tetap memanggil requireRole('admin').
Password Disimpan Plain Text
Jangan simpan password asli di database. Gunakan password_hash() saat menyimpan dan password_verify() saat login.
Lupa session_start()
Session harus dimulai sebelum membaca atau menulis $_SESSION. Helper auth.php di atas sudah menangani ini dengan session_status().
Role Tidak Dicek Setelah Login
Login hanya menjawab "siapa user ini". Role menjawab "boleh melakukan apa". Keduanya harus dipisahkan.
Redirect Setelah Login Tidak Diikuti exit
Setelah header('Location: ...'), selalu panggil exit agar kode di bawahnya tidak ikut berjalan.
FAQ
Apakah role harus memakai ENUM?
Tidak wajib. Bisa juga memakai tabel roles terpisah. Untuk project pemula, ENUM cukup sederhana. Untuk aplikasi besar, tabel role lebih fleksibel.
Apakah admin boleh mengubah role dirinya sendiri?
Sebaiknya hati-hati. Di aplikasi nyata, perubahan role admin perlu validasi tambahan agar tidak mengunci semua akun admin.
Apakah halaman user biasa perlu requireRole('user')?
Kalau semua user login boleh masuk, cukup requireLogin(). Pakai requireRole() ketika halaman hanya boleh untuk role tertentu.
Bagaimana kalau satu user punya banyak role?
Gunakan tabel relasi seperti user_roles. Panduan ini memakai satu role per user agar konsep dasarnya mudah dipahami dulu.
Bacaan Terkait