Sunday, 21 June 2026

PHP Authentication with Secured Admin Dashboard

Building an authentication system with a secure admin dashboard involves a few critical steps: validating credentials against the database, managing sessions to protect secure pages, and building a clean, responsive layout.

Based on your ER model, we will use the admins table for this implementation.



Step 1: Database Connection Setup (db.php)

First, create a reusable database connection script. According to your ER diagram notes, the database name is belajarefektif, the username is root, and there is no password.

PHP

<?php
// db.php
$host = 'localhost';
$db   = 'belajarefektif';
$user = 'root';
$pass = '';
$charset = 'utf8mb4';

$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

try {
     $pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
     throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
?>

Step 2: The Login Page (login.php)

This page handles both rendering the login form (styled with Bootstrap 5) and processing the authentication request. It safely verifies the email and password using password hashing (password_verify).

PHP

<?php
// login.php
session_start();
require 'db.php';

// Redirect if already logged in
if (isset($_SESSION['admin_id'])) {
    header("Location: main.php");
    exit;
}

$error = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $email = trim($_POST['email']);
    $password = trim($_POST['password']);

    if (!empty($email) && !empty($password)) {
        // Prepare statement using the 'admins' table fields from your ER model
        $stmt = $pdo->prepare('SELECT adminId, fullName, password FROM admins WHERE email = ?');
        $stmt->execute([$email]);
        $admin = $stmt->fetch();

        // Verify password (Assumes you stored passwords using password_hash() in PHP)
        if ($admin && password_verify($password, $admin['password'])) {
            // Regenerate session ID for security (prevents session fixation)
            session_regenerate_id(true);
            
            $_SESSION['admin_id'] = $admin['adminId'];
            $_SESSION['admin_name'] = $admin['fullName'];
            
            header("Location: main.php");
            exit;
        } else {
            $error = 'Invalid email or password.';
        }
    } else {
        $error = 'Please fill in all fields.';
    }
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Admin Login - Training Management System</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body { background-color: #f8f9fa; }
        .login-container { max-width: 400px; margin-top: 10%; }
    </style>
</head>
<body>

<div class="container login-container">
    <div class="card shadow-sm">
        <div class="card-header bg-primary text-white text-center py-3">
            <h5 class="mb-0">TMS Admin Login</h5>
        </div>
        <div class="card-body p-4">
            <?php if (!empty($error)): ?>
                <div class="alert alert-danger"><?= htmlspecialchars($error) ?></div>
            <?php endif; ?>

            <form action="login.php" method="POST">
                <div class="mb-3">
                    <label for="email" class="form-label">Email Address</label>
                    <input type="email" name="email" id="email" class="form-control" required>
                </div>
                <div class="mb-3">
                    <label for="password" class="form-label">Password</label>
                    <input type="password" name="password" id="password" class="form-control" required>
                </div>
                <button type="submit" class="btn btn-primary w-100 mt-2">Login</button>
            </form>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Note on Password Setup: To insert an admin user into your database for testing, hash the password first via PHP:

echo password_hash("yourpassword", PASSWORD_BCRYPT);

Then insert that resulting string directly into the password column of the admins table.

Step 3: Secure Page Session Protection (auth.php)

Instead of writing protection logic on every single secure page, create a helper script that you can include at the top of any page requiring authentication.

PHP

<?php
// auth.php
session_start();

// Check if user session exists
if (!isset($_SESSION['admin_id'])) {
    // Redirect to login page if not authenticated
    header("Location: login.php");
    exit;
}
?>

Step 4: The Secure Admin Dashboard Layout (main.php)

By including auth.php, this page is securely locked down. The layout features a Bootstrap 5 fixed top navigation bar, a fixed sidebar, and a scrollable main content window.

PHP

<?php
// main.php
require 'auth.php';
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Admin Dashboard - TMS</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" rel="stylesheet">
    <style>
        body {
            padding-top: 56px; /* Offset for fixed navbar */
            overflow-x: hidden;
        }
        /* Fixed Sidebar Styling */
        .sidebar {
            position: fixed;
            top: 56px;
            bottom: 0;
            left: 0;
            z-index: 1000;
            padding: 20px 0 0;
            box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
            width: 240px;
            background-color: #212529;
        }
        .sidebar .nav-link {
            font-weight: 500;
            color: #dee2e6;
        }
        .sidebar .nav-link:hover, .sidebar .nav-link.active {
            color: #fff;
            background-color: #343a40;
        }
        /* Main Content Layout offset */
        .main-content {
            margin-left: 240px;
            padding: 20px;
        }
        @media (max-width: 768px) {
            .sidebar { position: static; width: 100%; height: auto; }
            .main-content { margin-left: 0; }
        }
    </style>
</head>
<body>

<nav class="navbar navbar-dark bg-dark fixed-top flex-md-nowrap p-2 shadow">
    <a class="navbar-brand col-md-3 col-lg-2 me-0 px-3" href="#">Training Management System</a>
    <div class="navbar-nav px-3">
        <div class="nav-item text-nowrap d-flex align-items-center">
            <span class="text-light me-3">Welcome, <?= htmlspecialchars($_SESSION['admin_name']); ?></span>
            <a class="btn btn-sm btn-outline-danger" href="logout.php">Logout</a>
        </div>
    </div>
</nav>

<div class="container-fluid">
    <div class="row">
        <nav class="sidebar d-md-block collapse">
            <div class="position-sticky">
                <ul class="nav flex-column">
                    <li class="nav-item">
                        <a class="nav-link active" href="main.php">
                            <i class="bi bi-speedometer2 me-2"></i> Dashboard
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">
                            <i class="bi bi-people me-2"></i> Trainers
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">
                            <i class="bi bi-mortarboard me-2"></i> Courses
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">
                            <i class="bi bi-calendar-event me-2"></i> Sessions
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">
                            <i class="bi bi-person-badge me-2"></i> Customers
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">
                            <i class="bi bi-card-checklist me-2"></i> Enrollments
                        </a>
                    </li>
                </ul>
            </div>
        </nav>

        <main class="main-content">
            <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
                <h1 class="h2">Dashboard Summary</h1>
            </div>

            <div class="row g-3">
                <div class="col-md-4">
                    <div class="card text-white bg-primary mb-3">
                        <div class="card-body">
                            <h5 class="card-title">Manage Courses</h5>
                            <p class="card-text">Oversee active training packages and track constraints.</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-4">
                    <div class="card text-white bg-success mb-3">
                        <div class="card-body">
                            <h5 class="card-title">Active Enrollments</h5>
                            <p class="card-text">Monitor student registration pipelines and payments.</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-4">
                    <div class="card text-white bg-warning mb-3">
                        <div class="card-body">
                            <h5 class="card-title">Scheduled Sessions</h5>
                            <p class="card-text">Track schedules, assigned trainers, and classroom sizes.</p>
                        </div>
                    </div>
                </div>
            </div>
        </main>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Step 5: Secure Logging Out (logout.php)

To fully terminate the active session and secure the workstation when logging out:

PHP

<?php
// logout.php
session_start();

// Unset all session variables
$_SESSION = array();

// Destroy the actual session cookie in the browser
if (ini_get("session.use_cookies")) {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]
    );
}

// Destroy the session context on the server
session_destroy();

// Redirect back to login screen
header("Location: login.php");
exit;
?>

No comments:

Post a Comment