Role based user access control is one of the most significant feature of modern systems. Because its restrict user to show unnecessary information. User access control shows relevant information to user. Only admin or super user has all the rights to see, insert, update and delete information from system.
If I talk about wordpress, it has 4 major user roles which are Administrator, Editor, Author and Contributor. All 4 have different behaviors and access control but administrator user has all the rights in wordpress. User with this role can do anything from writing post to delete post, add theme to delete theme, add user to delete user.
So in this post I will create simple role based access control using php and mysqli.My purpose is to give you an idea about how these types of system develop and I hope this post will be going to help you in your future development.
What I am going to do:
I will create wordpress like user access level in which I will hide and show menu items according to user role.For this I will store user data into session.I will use login and inner page of free html5 bootstrap admin template. I will also break inner page into multiple php files like header, footer, and sidebar.
Admin Template Link:
https://startbootstrap.com/template-overviews/sb-admin/
Folder Structure:
File/Folder | Description |
---|---|
Index.php | This is a login page |
Dashboard.php | After successful login, User will land on this page. |
Assets Folder | This folder has css, js, bootstarp and plugins file |
Inc Folder | This folder has config.php file in which there is a database connection and getUserAccessRoleByID() function. |
Layouts Folder | This folder has 3 files footer.php, header,left_sidebar.php. I split static content of admin template in these files. |
Create database:
1 2 3 |
Create database demo; |
Mysql Tables with Data:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
CREATE TABLE IF NOT EXISTS `tbl_user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_role` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1; -- Dumping data for table demo.tbl_user_role: ~0 rows (approximately) /*!40000 ALTER TABLE `tbl_user_role` DISABLE KEYS */; INSERT INTO `tbl_user_role` (`id`, `user_role`) VALUES (1, 'admin'); INSERT INTO `tbl_user_role` (`id`, `user_role`) VALUES (2, 'editor'); INSERT INTO `tbl_user_role` (`id`, `user_role`) VALUES (3, 'author'); INSERT INTO `tbl_user_role` (`id`, `user_role`) VALUES (4, 'contributor'); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
CREATE TABLE IF NOT EXISTS `tbl_users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_role_id` int(11) DEFAULT NULL, `first_name` varchar(255) DEFAULT NULL, `last_name` varchar(255) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) INSERT INTO `tbl_users` (`id`, `user_role_id`, `first_name`, `last_name`, `email`, `password`) VALUES (1, 1, 'john', 'doe', 'john_doe@example.com', '0192023a7bbd73250516f069df18b500'); INSERT INTO `tbl_users` (`id`, `user_role_id`, `first_name`, `last_name`, `email`, `password`) VALUES (2, 2, 'ahsan', 'zameer', 'ahsan@example.com', '3d68b18bd9042ad3dc79643bde1ff351'); INSERT INTO `tbl_users` (`id`, `user_role_id`, `first_name`, `last_name`, `email`, `password`) VALUES (3, 3, 'sarah', 'khan', 'sarah@example.com', 'ec26202651ed221cf8f993668c459d46'); INSERT INTO `tbl_users` (`id`, `user_role_id`, `first_name`, `last_name`, `email`, `password`) VALUES (4, 4, 'salman', 'ahmed', 'salman@example.com', '97502267ac1b12468f69c14dd70196e9'); |
Database Connection (config.php):
Config file has database connection and getUserAccessRoleByID
function which takes user_role
id and returns role name.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<!--?php define("HOST","localhost"); define("DB_USER","root"); define("DB_PASS",""); define("DB_NAME","demo"); $conn = mysqli_connect(HOST,DB_USER,DB_PASS,DB_NAME); if(!$conn) { die(mysqli_error()); } functiongetUserAccessRoleByID($id) { global $conn; $query = "select user_role from tbl_user_rolewhere id = ".$id; $rs = mysqli_query($conn,$query); $row = mysqli_fetch_assoc($rs); return $row['user_role']; } ?--> |
Login Page (index.php):
I use session_start() function on very first line then include config file which is under inc folder. Then on the next line there is a login condition that match email and password into the table and if user and password exist then I will create session and send user to dashboard.php page otherwise I already set error. I pass whole row except password to the $_SESSION
. After that you will see 2 more conditions,one is for logout and second is for displaying direct dashboard access restriction message. After that there is html.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
<!--?php session_start(); require_once('inc/config.php'); if(isset($_POST['login'])) { if(!empty($_POST['email']) && !empty($_POST['password'])) { $email = trim($_POST['email']); $password = trim($_POST['password']); $md5Password = md5($password); $sql = "select * from tbl_users where email = '".$email."' and password = '".$md5Password."'"; $rs = mysqli_query($conn,$sql); $getNumRows = mysqli_num_rows($rs); if($getNumRows == 1) { $getUserRow = mysqli_fetch_assoc($rs); unset($getUserRow['password']); $_SESSION = $getUserRow; header('location:dashboard.php'); exit; } else { $errorMsg = "Wrong email or password"; } } } if(isset($_GET['logout']) && $_GET['logout'] == true) { session_destroy(); header("location:index.php"); exit; } if(isset($_GET['lmsg']) && $_GET['lmsg'] == true) { $errorMsg = "Login required to access dashboard"; } ?--> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>Simple role based access control example using php and mysqli</title> <!-- Bootstrap core CSS--> <link href="assets/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"> <!-- Custom fonts for this template--> <link href="assets/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css"> <!-- Custom styles for this template--> <link href="assets/css/sb-admin.css" rel="stylesheet"> <div class="container"> <div class="card card-login mx-auto mt-5"> <div class="card-header">Login</div> <div class="card-body"> <!--?php if(isset($errorMsg)) { echo ' <div class="alert alert-danger"-->'; echo $errorMsg; echo '</div> '; unset($errorMsg); } ?> <form action="<?php echo $_SERVER['PHP_SELF']?>" method="post"> <div class="form-group"> <label for="exampleInputEmail1">Email address</label> <input class="form-control" id="exampleInputEmail1" name="email" type="email" placeholder="Enter email" required=""> </div> <div class="form-group"> <label for="exampleInputPassword1">Password</label> <input class="form-control" id="exampleInputPassword1" name="password" type="password" placeholder="Password" required=""> </div> <button class="btn btn-primary btn-block" type="submit" name="login">Login</button> </form> </div> </div> <!-- Bootstrap core JavaScript--> <script src="assets/vendor/jquery/jquery.min.js"></script> <script src="assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script> <!-- Core plugin JavaScript--> <script src="assets/vendor/jquery-easing/jquery.easing.min.js"></script> |
Dashboard Page (dashboard.php):
In the dashboard.php first I start a session, then I add a condition in which, if any user try to access dashboard.php directly he/she will return to login page. Then I include 3 files config.php
, header.php
and left_sidebar.php
. getUserAccessRoleByID()
function get the user role id and return role name.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<!--?php session_start(); if(!isset($_SESSION['id'],$_SESSION['user_role_id'])) { header('location:index.php?lmsg=true'); exit; } require_once('inc/config.php'); require_once('layouts/header.php'); require_once('layouts/left_sidebar.php'); ?--> <div class="content-wrapper"> <div class="container-fluid"> <!-- Breadcrumbs--> <ol class="breadcrumb"> <li class="breadcrumb-item"> <a href="#">Dashboard</a> </li> </ol> <h1>Welcome to Dashboard</h1> <hr> You are login as <strong><!--?php echo getUserAccessRoleByID($_SESSION['user_role_id']); ?--></strong> <ul> <li><strong>John Doe</strong> has <strong>Administrator</strong> rights so all the left bar items are visible to him</li> <li><strong>Ahsan</strong> has <strong>Editor</strong> rights and he doesn't have access to Settings</li> <li><strong>Sarah</strong> has <strong>Author</strong> rights and she can't have access to Appearance, Components and Settings</li> <li><strong>Salman</strong> has <strong>Contributor</strong> rights and he has only access Posts</li> </ul> <div style="height: 1000px;"></div> </div> <!-- /.container-fluid--> <!--?php require_once('layouts/footer.php'); ?--> </div> |
Left Sidebar (left_sidebar.php):
$_SESSION['user_role_id']
holds user role id. I put static condition on left sidebar menu items according to user role. Posts is the only item which are visible to every one so there is no need to wrap it under condition. Pages and categories are only hide from Contributor. Appearance and Components section are available for Administrator and Editor. Settings section is only available to Administrator user.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
<!-- Navigation--> <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" id="mainNav"> <a class="navbar-brand" href="dashboard.php"></a> <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarResponsive"> <ul class="navbar-nav navbar-sidenav" id="exampleAccordion"> <li class="nav-item" data-toggle="tooltip" data-placement="right" title="Dashboard"> <a class="nav-link" href="dashboard.php"> <i class="fa fa-fw fa-dashboard"></i> <span class="nav-link-text">Dashboard</span> </a> </li> <li class="nav-item" data-toggle="tooltip" data-placement="right" title="Charts"> <a class="nav-link" href="#"> <i class="fa fa-fw fa fa-wpforms"></i> <span class="nav-link-text">Posts</span> </a> </li> <!--?php //only visible to admin and editor if($_SESSION['user_role_id'] != 4){?--> <li class="nav-item" data-toggle="tooltip" data-placement="right" title="Charts"> <a class="nav-link" href="#"> <i class="fa fa-fw fa fa-copy"></i> <span class="nav-link-text">Pages</span> </a> </li> <li class="nav-item" data-toggle="tooltip" data-placement="right" title="Tables"> <a class="nav-link" href="#"> <i class="fa fa-fw fa-circle-o-notch"></i> <span class="nav-link-text">Categoris</span> </a> </li> <!--?php }?--> <!--?php //only visible to admin and editor if(($_SESSION['user_role_id'] == 1) || $_SESSION['user_role_id'] == 2 ){?--> <li class="nav-item" data-toggle="tooltip" data-placement="right" title="Components"> <a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#collapseComponents" data-parent="#exampleAccordion"> <i class="fa fa-fw fa-wrench"></i> <span class="nav-link-text">Appearance</span> </a> <ul class="sidenav-second-level collapse" id="collapseComponents"> <li> <a href="#">Themes</a> </li> <li> <a href="#">Menus</a> </li> </ul> </li> <li class="nav-item" data-toggle="tooltip" data-placement="right" title="Example Pages"> <a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#collapseExamplePages" data-parent="#exampleAccordion"> <i class="fa fa-fw fa-file"></i> <span class="nav-link-text">Components</span> </a> <ul class="sidenav-second-level collapse" id="collapseExamplePages"> <li> <a href="#">Login Page</a> </li> <li> <a href="#">Registration Page</a> </li> <li> <a href="#">Forgot Password Page</a> </li> <li> <a href="#">Blank Page</a> </li> </ul> </li> <!--?php } ?--> <!--?php //only visible to admin if($_SESSION['user_role_id'] == 1){?--> <li class="nav-item" data-toggle="tooltip" data-placement="right" title="Link"> <a class="nav-link" href="#"> <i class="fa fa-fw fa fa-gear"></i> <span class="nav-link-text">Settings</span> </a> </li> <!--?php } ?--> </ul> <ul class="navbar-nav ml-auto"> <li class="nav-item"> <a class="nav-link" href="index.php?logout=true"> <i class="fa fa-fw fa-sign-out"></i>Logout </a> </li> </ul> </div> </nav> |
Also read:
- 10 PHP Url Functions – Every beginner must check
- jQuery form validation example without plugin
- How to create CRUD in Codeigniter
- How to sort html table columns using PHP jQuery and Ajax
- User Registration in PHP
Parse error: syntax error, unexpected ‘global’ (T_GLOBAL) in /Applications/XAMPP/xamppfiles/htdocs/!delete_demo/config.php on line 17
Found the same issue. Fixed by changing line 15 from functiongetUserAccessRoleByID($id) to function functiongetUserAccessRoleByID($id)
You missed the point of the function, “getUserAccessRoleByID”
hello sorry for me very bad english, i have a question, why not use only if($_GET[‘lmsg’] == true), on direct dashboard access restriction message? rather than if(isset($_GET[‘lmsg’]) && $_GET[‘lmsg’] == true)
Great tut. However, I get too many redirects.
This is 2018, and you’re using MD5?
Code working well with me..
but how about if I got button like add/delete/update and 1 user id got diff role to use this button.
exm : Department Human Resource
John as staff only can update profile
Doe as supervisor can update / add new profile
Zack as manager have the right to add and delete any profile.
exm : Department Finance
John as Account Clerk only add new invoice
Doe as supervisor can add and update invoice
Zack as manager have the right to add and delete any invoice.
Sorry for my bad english and long question.