Сегодня я хочу рассказать вам об организации прав доступа пользователей (на вашем сайте) с помощью битовых масок. Возможно, вы уже знаете это, возможно, нет, но в любом случае я хочу дать вам эту информацию. Почему битовые маски? — легко, потому что это быстрый и простой способ распознать возможные действия пользователя. В нашей системе я определил шесть возможных действий (в нем будет 6 битов, где каждый бит является одним из возможных действий). Это следующие действия: чтение, создание, редактирование своего, удаление собственного, редактирование любого и удаление любого (действия модератора / администратора). Этот метод может применяться ко всему — блогам, новостным статьям, фотографиям и многому другому. Хорошо, давайте начнем.
Вот небольшая теория о побитовых операторах:
пример | название | Результат |
---|---|---|
$ a & $ b | И | Биты, которые установлены как в $ a, так и в $ b, установлены. |
$ a | $ б | Или (включительно или) | Биты, которые установлены в $ a или $ b, установлены. |
$ a ^ $ b | Xor (эксклюзив или) | Биты, которые установлены в $ a или $ b, но не оба установлены. |
~ $ a | Не | Биты, которые установлены в $ a, не устанавливаются, и наоборот. |
$ a << $ b | Сдвиг влево | Сдвиньте биты $ a $ b шагов влево (каждый шаг означает «умножить на два») |
$ a >> $ b | Сдвиг вправо | Сдвиньте биты шагов $ a $ b вправо (каждый шаг означает «разделить на два») |
Live Demo
скачать в упаковке
Теперь загрузите исходные файлы и начните кодировать!
Шаг 1. HTML
Наше демо использует 3 html файла шаблона:
main_page.html
<!DOCTYPE html> <html lang="en" > <head> <title>Access Control with Bit Masks</title> <link href="css/main.css" rel="stylesheet" type="text/css" /> </head> <body> <header> <h2>Access Control with Bit Masks</h2> <a href="http://www.script-tutorials.com/access-control-with-bit-masks/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a> </header> <div class="container"> {form} </div> </body> </html>
Это очень простой макет, не так ли? Следующий файл шаблона:
login_form.html
<div class="column"> <h3>Access control demonstration</h3> <p>You can use next usernames "User", "Writer", "Moderator" and "Admin" and password "password" to login in system. Each of them have own set of possibilities.</p> </div> <div class="column"> <form class="login_form" action="index.php" method="post"> <h3>Log In</h3> <label>Username:</label><input type="text" name="username"> <label>Password:</label><input type="password" name="password"> <input type="submit" name="LogIn" value="Login"> </form> </div>
Еще один простой шаблон для формы входа. Следующий файл шаблона:
logout_form.html
<div class="column"> <h3>Hello {name}</h3> <h3>Your bit mask:</h3> <div>{bit_mask}</div> <h3>Your possibilities:</h3> <div>{possibilities}</div> </div> <div class="column"> <a href="index.php?logout">Log Out</a> </div>
Это шаблон, в котором мы будем отображать возможности пользователя и ссылку на выход из системы.
Шаг 2. CSS
CSS / main.css
Этот файл содержит несколько стилей нашего макета страницы, нет необходимости публиковать его сегодня.
Шаг 3. PHP
Теперь давайте рассмотрим наш основной функционал:
index.php
<?php // define bit mask for access rights define('CAN_READ', 1 << 0); // 000001 define('CAN_CREATE', 1 << 1); // 000010 define('CAN_EDIT_OWN', 1 << 2); // 000100 define('CAN_DELETE_OWN', 1 << 3); // 001000 define('CAN_EDIT_ANY', 1 << 4); // 010000 define('CAN_DELETE_ANY', 1 << 5); // 100000 // login system init and generation code $oSimpleAccessSystem = new SimpleAccessSystem(); $sLoginForm = $oSimpleAccessSystem->getLoginBox(); echo strtr(file_get_contents('main_page.html'), array('{form}' => $sLoginForm)); // class SimpleAccessSystem class SimpleAccessSystem { // variables var $aMembers; // Existed members array // constructor function SimpleAccessSystem() { session_start(); // different sets of permissions $sUserPerm = CAN_READ; $sWriterPerm = CAN_READ | CAN_CREATE | CAN_EDIT_OWN | CAN_DELETE_OWN; $sModeratorPerm = CAN_READ | CAN_EDIT_ANY | CAN_DELETE_ANY; $sAdminPerm = CAN_READ | CAN_CREATE | CAN_EDIT_OWN | CAN_DELETE_OWN | CAN_EDIT_ANY | CAN_DELETE_ANY; /* hash = sha1(md5('password') . 'testing'); */ $this->aMembers = array( 'User' => array('hash' => 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'salt' => 'testing', 'rule' => $sUserPerm), 'Writer' => array('hash' => 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'salt' => 'testing', 'rule' => $sWriterPerm), 'Moderator' => array('hash' => 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'salt' => 'testing', 'rule' => $sModeratorPerm), 'Admin' => array('hash' => 'b88c654d6c68fc37f4dda1d29935235eea9a845b', 'salt' => 'testing', 'rule' => $sAdminPerm) ); } // get login box function function getLoginBox() { if (isset($_GET['logout'])) { // logout processing if (isset($_SESSION['member_name']) && isset($_SESSION['member_pass'])) $this->performLogout(); } if ($_POST && $_POST['username'] && $_POST['password']) { // login processing if ($this->checkLogin($_POST['username'], $_POST['password'], false)) { // successful login $this->performLogin($_POST['username'], $_POST['password']); header( "Location:{$_SERVER['REQUEST_URI']}" ); exit; } else { // wrong login ob_start(); // get template of Login form require_once('login_form.html'); $sLoginForm = ob_get_clean(); return $sLoginForm . '<h2>Username or Password is incorrect</h2>'; } } else { // in case if we already logged (on refresh page): if (isset($_SESSION['member_name']) && $_SESSION['member_name'] && $_SESSION['member_pass']) { if ($this->checkLogin($_SESSION['member_name'], $_SESSION['member_pass'])) { $sRule = $this->aMembers[$_SESSION['member_name']]['rule']; $sPermissions = ''; $sPermissions .= $this->isCanRead($sRule); $sPermissions .= $this->isCanCreate($sRule); $sPermissions .= $this->isCanEdit($sRule); $sPermissions .= $this->isCanEditAny($sRule); $sPermissions .= $this->isCanDelete($sRule); $sPermissions .= $this->isCanDeleteAny($sRule); ob_start(); // get template of Logout form require_once('logout_form.html'); $sLogoutForm = ob_get_clean(); $sLogoutForm = str_replace('{name}', $_SESSION['member_name'], $sLogoutForm); $sLogoutForm = str_replace('{bit_mask}', $sRule, $sLogoutForm); $sLogoutForm = str_replace('{possibilities}', $sPermissions, $sLogoutForm); return $sLogoutForm; } } // otherwise - draw login form ob_start(); require_once('login_form.html'); $sLoginForm = ob_get_clean(); return $sLoginForm; } } // check functions function isCanRead($sRule) { return ($sRule & CAN_READ) ? 'You can Read<br />' : ''; } function isCanCreate($sRule) { return ($sRule & CAN_CREATE) ? 'You can Create<br />' : ''; } function isCanEdit($sRule) { return ($sRule & CAN_EDIT_OWN) ? 'You can Edit<br />' : ''; } function isCanEditAny($sRule) { return ($sRule & CAN_EDIT_ANY) ? 'You can Edit anything<br />' : ''; } function isCanDelete($sRule) { return ($sRule & CAN_DELETE_OWN) ? 'You can Delete<br />' : ''; } function isCanDeleteAny($sRule) { return ($sRule & CAN_DELETE_ANY) ? 'You can Delete anything<br />' : ''; } // perform login function performLogin($sName, $sPass) { $this->performLogout(); $sSalt = $this->aMembers[$sName]['salt']; $sPass = sha1(md5($sPass) . $sSalt); $_SESSION['member_name'] = $sName; $_SESSION['member_pass'] = $sPass; } // perform logout function performLogout() { unset($_SESSION['member_name']); unset($_SESSION['member_pass']); } // check login function checkLogin($sName, $sPass, $isHash = true) { if (isset($this->aMembers[$sName])) { if (! $isHash) { $sSalt = $this->aMembers[$sName]['salt']; $sPass = sha1(md5($sPass) . $sSalt); } return ($sPass == $this->aMembers[$sName]['hash']); } return false; } }
Сначала мы определяем константы для прав доступа (битовая маска). Далее, когда мы перечисляем пользователей в системе — мы предоставляем им разные наборы прав (используя логический оператор | или). Имейте в виду, что я не заставляю вас держать пользователей в одном массиве, в вашем случае ваши пользователи могут легко находиться в базе данных. И, в этом случае, вы можете предоставить им их право в самой базе данных. Кроме того, я добавил дополнительные функции проверки, чтобы мы могли понять, может ли пользователь выполнить определенное действие.
В таких функциях мы используем логический оператор & (и). В большинстве этих проверок используется проверка одного бита. Если вы хотите сделать несколько проверок, например — давайте создадим функцию, чтобы проверить, может ли член читать и создавать. Тогда эта функция будет выглядеть так:
function isCanReadCreate($sRule) { return ($sRule & (CAN_READ | CAN_CREATE)); }
Эта функция вернет True или False.
Live Demo
скачать в архиве
Вывод
Надеюсь, вам было интересно вспомнить, как работают побитовые и логические операнды. Если у вас есть хорошие идеи, которыми вы хотели бы поделиться, обязательно напишите нам. Удачи!
Источник: http://www.script-tutorials.com/access-control-with-bit-masks/