πŸ“– Protecting Pages by Role with PHP MVC

Why We Use Role-Based Access

Authentication answers the question, β€œWho are you?” β€” typically handled during login. Authorization answers, β€œWhat can you do?” β€” and that's where roles come in.

In our CodeStream simulation, users are assigned a role when they register or log in. That role (e.g., 'user' or 'admin') is stored in the session and used throughout the app to control access.

Session-Based Role Checks

Once a user logs in, their role is saved to $_SESSION. This allows you to protect routes or logic by checking their role on each request.


// login_user() - part of login controller logic
$_SESSION['role'] = $user['role'];

Later in your app, you can check for this role:

if ($_SESSION['role'] !== 'admin') {
    header("Location: index.php?error=" . urlencode("Access denied."));
    exit;
}

This logic prevents unauthorized users from continuing β€” and it’s critical for all admin-only routes or actions.

Protecting Entire Pages

To lock down a full page like the admin dashboard, include a session check at the top of the entry point file, such as admin/dashboard.php. This prevents access before any output is sent to the browser.

<?php
require_once BASE_PATH . '/config/init.php';
require_once BASE_PATH . '/controllers/UserController.php';

if ($_SESSION['role'] !== 'admin') {
    header("Location: index.php?error=" . urlencode("Admins only."));
    exit;
}

UserController::dashboard();

πŸ’‘ Tip: Always include init.php at the top of restricted pages to ensure the session is active before accessing $_SESSION variables.

Other Pages to Secure

While admin dashboards are obvious candidates for role protection, here are other page types that typically require access control:

  • edit.php β€” Only the user who owns the profile (or an admin) should edit it
  • delete.php β€” Requires both ownership and admin checks
  • deactivate.php β€” Users can deactivate their own account, but not others
  • admin/user.php β€” Admin-only view of all registered users
  • settings.php β€” Should check for a logged-in session before showing preferences

To allow either admins or the profile owner, you can combine two conditions using the && operator:

if ($_SESSION['role'] !== 'admin' && $_SESSION['userID'] !== $user['id']) {
    header("Location: profile.php?error=" . urlencode("You do not have permission to edit this profile."));
    exit;
}

This condition means: if you're not an admin and you don't own the profile, you're blocked. The && operator means both conditions must be true to trigger the redirect. If either is false β€” for example, the user is an admin or the profile owner β€” access is allowed.

Restricting Buttons or Actions

In your views, you may want to hide sensitive actions β€” such as "Edit User", "Delete", or "Manage Roles" β€” from non-admins. Use a simple PHP conditional inside the HTML to control visibility:

<?php if ($_SESSION['role'] === 'admin'): ?>
  <a href="delete.php?id=<?= $user['id'] ?>" class="btn btn-danger">Delete User</a>
<?php endif; ?>

This ensures that regular users won’t even see the link. But that’s not enough β€” you must also enforce role checks in the controller.

if ($_SESSION['role'] !== 'admin') {
    header("Location: profile.php?error=" . urlencode("Unauthorized action."));
    exit;
}

In your shared header file (e.g. views/partials/header.php), you can dynamically show navigation links depending on the user's login status. This improves clarity and prevents user error, such as offering a Register button to someone who is already logged in.

<?php if (isset($_SESSION['userID'])): ?>
  <a href="profile.php?logout" class="btn btn-success">Logout</a>
<?php else: ?>
  <a href="register.php" class="btn btn-success">Register</a>
  <a href="login.php" class="btn btn-success">Sign In</a>
<?php endif; ?>

Combine this with a personalized greeting (as shown in the Sessions and Cookies article) using $displayName from the init.php file.

Using Shorthand Auth Helpers

To simplify your access logic, you can define small helper functions once in config/init.php and use them anywhere in your app β€” views, controllers, or entry scripts. These helpers replace repetitive checks like isset($_SESSION['userID']) or $_SESSION['role'] !== 'admin' with more readable versions:

// config/init.php

function isLoggedIn() {
    return isset($_SESSION['userID']);
}

function isAdmin() {
    return isset($_SESSION['role']) && $_SESSION['role'] === 'admin';
}

function isUser($id) {
    return isset($_SESSION['userID']) && $_SESSION['userID'] == $id;
}

Use these anywhere you need to check login or access status β€” whether to show a button, protect a controller, or personalize a view.

πŸ” Replacing Common Checks

// Before: checking login status to show or hide links
<?php if (isset($_SESSION['userID'])): ?>
  <a href="logout.php">Logout</a>
<?php else: ?>
  <a href="login.php">Sign In</a>
<?php endif; ?>

// After:
<?php if (isLoggedIn()): ?>
  <a href="logout.php">Logout</a>
<?php else: ?>
  <a href="login.php">Sign In</a>
<?php endif; ?>
// Before: checking role before showing admin-only button
<?php if ($_SESSION['role'] === 'admin'): ?>
  <a href="delete.php?id=<?= $user['id'] ?>">Delete</a>
<?php endif; ?>

// After:
<?php if (isAdmin()): ?>
  <a href="delete.php?id=<?= $user['id'] ?>">Delete</a>
<?php endif; ?>
// Before: controller logic to protect edit route
if ($_SESSION['role'] !== 'admin' && $_SESSION['userID'] !== $user['id']) {
    header("Location: profile.php?error=" . urlencode("Unauthorized."));
    exit;
}

// After:
if (!isAdmin() && !isUser($user['id'])) {
    header("Location: profile.php?error=" . urlencode("Unauthorized."));
    exit;
}

These helpers reduce repetition and make your intentions more obvious. Whether you're displaying a button, rendering a form, or enforcing backend logic β€” use isLoggedIn(), isAdmin(), and isUser($id) to keep your code secure and readable.

Team Guidelines

  • βœ… Always check $_SESSION['role'] before executing admin logic
  • βœ… Use server-side redirects to block unauthorized users
  • βœ… Use conditionals in views to hide admin-only buttons or links
  • ⚠️ Never trust the front-end alone β€” always verify roles server-side

Following these standards ensures that your app behaves securely β€” even if someone tries to bypass the UI manually.

Summary / Takeaways

  • πŸ›‘οΈ Use session-based roles to authorize user actions
  • πŸ—‚οΈ Protect entire pages with role checks at the entry point
  • 🧼 Hide admin UI elements using PHP logic in the view
  • 🧠 Always back up UI restrictions with controller checks
  • 🧩 Define small helper functions for access logic

Additional Resources

Last updated: August 8, 2025 at 8:56 PM