π 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 itdelete.phpβ Requires both ownership and admin checksdeactivate.phpβ Users can deactivate their own account, but not othersadmin/user.phpβ Admin-only view of all registered userssettings.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;
}
Controlling Header Links by Session
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