От автора: Большинство учебников имеют дело только с установлением личности пользователя, что позволяет учитывать два уровня безопасности: вошедших в систему и не вошедших. Для многих сайтов необходим более совершенный уровень контроля для руководства тем, куда пользователям можно зайти и что можно делать. Создание списка системы контроля доступа (ACL) даст вам возможность применить гибкость в управлении правами доступа.
Перед тем, как мы приступим к созданию списка контроля доступа на сайт, я Вам рекомендую скачать исходники.
Вступление
Представьте себе, что вы запускаете большой обучающий сайт, из которого пользователи могут узнать о всем многообразии методов разработки Сети. Вдобавок к своим обычным читателям у вас есть элитные подписчики, а также сотрудничающие авторы и администраторы.
Ваша проблема:
Вы хотите ограничить посещение пользователей только теми страницами, к которым есть доступ согласно их аккаунта.
Решение:
Выполнение списка контроля доступа позволит осуществлять управление возможностью пользователей получить доступ к чему-либо в вашем сайте или не получить.
При просмотре демоверсии, доступной со скачиваемым исходным кодом, вас встретит классификационная страница (index page), которая определяет список контроля доступа (ACL) для каждого пользователя. Можно выбрать различные ссылки внизу страницы, чтобы просмотреть ACL для разных пользователей. Если щелкнуть на ссылку ‘Admin Screen’ вверху страницы, можно посмотреть пример интерфейса администратора, позволяющего управлять пользователями, ролевыми именами и правами доступа. ПРИМЕЧАНИЕ: система администратора будет выполнять обновление базы данных каждые 30 минут, чтобы убедиться, что все идет отлично.
Эта система даст возможность создавать разные группы пользователей (т.е. гостей, элитных пользователей, сотрудников и админов). Мы сможем установить уникальные права доступа для каждой группы, так же как и для отдельных пользователей. Давайте начнем с установки базы данных MySQL.
Шаг 1: создаем базу данных
Наша ACL будет храниться в родственной базе данных, использующей шесть таблиц (включая таблицу пользователей). У вас уже должна быть база данных, установленная в гостевой среде. Мы создадим вот такую структуру таблицы:
Код для создания базы данных доступен в исходных файлах (install.sql), а еще там присутствует другой файл (sampleData.sql), который создаст 4 пробных пользователя наряду с несколькими ролевыми именами и правами доступа, которых можно будет протестировать. Просто откройте файлы при помощи своего любимого текстового редактора и скопируйте/вставьте код в панель SQL в phpMyAdmin.
Шаг 2: присоединяем базу данных
Нам нужно создать включаемый файл для того, чтобы можно было соединяться со своей базой данных. Создайте файл с названием assets/php/database.php и добавьте в него следующий код (замените переменные величины на информацию, подходящую к своему хостинговому положению):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php session_start(); ob_start(); $hasDB = false; $server = 'localhost'; $user = 'root'; $pass = 'mysql'; $db = 'acl_test'; $link = mysql_connect($server,$user,$pass); if (!is_resource($link)) { $hasDB = false; die("Could not connect to the MySQL server at localhost."); } else { $hasDB = true; mysql_select_db($db); } ?> |
В первой строке кода мы вызываем session_start(); на самом деле мы не будем использовать переменные сеанса, но они понадобятся нам как часть системы пользовательских логинов. Затем мы вызываем ob_start() для создания выходного буфера. Обычно когда PHP создает страницу, она посылается на браузер в процессе образования. При использовании ob_start() страница и заголовки не посылаются на браузер, пока они полностью не загружены, или пока мы не вызовем ob_end_flush(). Буферизуя страницу, мы можем перенаправить использование PHP в любую точку на странице, а не только в ее начало. После высылки заголовков мы может перенаправлять только с помощью JavaScript. Инициативный хакер мог бы с легкостью выключить JavaScript и посмотреть нашу незащищенную страницу во всем ее великолепии. Эта единственная строка позволяет препятствовать пользовательскому доступу в любой своей части, если нужно.
Строки 4-8 устанавливают переменные. $hasDB — это булево выражение, используемое для определения наличия соединения. $server,$user, $pass, и $db – доказательства соединения для сервера. Строка 9 соединяет с сервером в то время, как строка 10 определяет, было ли соединение успешным. Если было, мы выбираем базу данных для использования; если нет, отображаем сообщение об ошибке при помощи die().
Шаг 3: создаем класс ACL
Этот шаг довольно длителен, так как мы создаем класс ACL, который сформирует основу нашей системы. Заранее извиняюсь за его протяженность.
Наша система ACL будет объектно-ориентированной, так что давайте стартуем с создания классификационного файла. Начинаем с добавления определения класса, определения переменной и проектировщика файла /assets/php/class.acl.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php class ACL { var $perms = array(); //Array : Stores the permissions for the user var $userID = 0; //Integer : Stores the ID of the current user var $userRoles = array(); //Array : Stores the roles of the current user function __constructor($userID = '') { if ($userID != '') { $this->userID = floatval($userID); } else { $this->userID = floatval($_SESSION['userID']); } $this->userRoles = $this->getUserRoles('ids'); $this->buildACL(); } function ACL($userID='') { $this->__constructor($userID); } |
Анализ:
После определения класса создаем три переменных класса для хранения информации, которая будет использоваться при создании ACL.
Прием конструирования:
Функция __constructor() употребляется для инициализации объекта, когда нам нужно загрузить ACL. Она автоматически именуется при вызове new ACL();. Затем ей передается единичный дополнительный аргумент пользователя, для которого загружается ACL. Внутри конструктора мы проверяем, был ли передан ID пользователя. Если никакого ID передано не было, предполагаем, что ACL будет загружаться для только что зарегистрированного пользователя; так что в переменной сеанса мы об этом прочтем. В противном случае, если мы передадим ID пользователя, это позволит нам читать и редактировать ACL для другого пользователя, не того, который зарегистрировался (пригодится для вашей страницы администратора).
После прочтения пользовательского ID мы вызываем getUserRoles() для формирования массива ролевых имен, присвоенных пользователю, и сохранения его в переменной класса $userRoles. В конце конструктора вызываем buildACL() для создания текущего ACL. Метод под названием ACL() – это опора для установок PHP4. При вызове new ACL() в PHP5 интерпретатор PHP запускает метод __constructor(). Однако, когда вы выполняете тот же код в PHP4, интерпретатор запускает ACL(). Обеспечивая метод, названный точно так же, как и класс, мы делаем класс PHP4 совместимым.
Каждый раз при создании нового объекта ACL путем передачи ID пользователя, этот объект будет содержать права доступа переданного пользователя.
Вспомогательные методы:
Теперь давайте добавим в тот же классификационный файл еще и вспомогательные методы. Выполняя специальные задания, они обеспечат поддержку остальных методов:
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 |
function getUserRoles() { $strSQL = "SELECT * FROM `user_roles` WHERE `userID` = " . floatval($this->userID) . " ORDER BY `addDate` ASC"; $data = mysql_query($strSQL); $resp = array(); while($row = mysql_fetch_array($data)) { $resp[] = $row['roleID']; } return $resp; } function getAllRoles($format='ids') { $format = strtolower($format); $strSQL = "SELECT * FROM `roles` ORDER BY `roleName` ASC"; $data = mysql_query($strSQL); $resp = array(); while($row = mysql_fetch_array($data)) { if ($format == 'full') { $resp[] = array("ID" => $row['ID'],"Name" => $row['roleName']); } else { $resp[] = $row['ID']; } } return $resp; } function buildACL() { //first, get the rules for the user's role if (count($this->userRoles) > 0) { $this->perms = array_merge($this->perms,$this->getRolePerms($this->userRoles)); } //then, get the individual user permissions $this->perms = array_merge($this->perms,$this->getUserPerms($this->userID)); } function getPermKeyFromID($permID) { $strSQL = "SELECT `permKey` FROM `permissions` WHERE `ID` = " . floatval($permID) . " LIMIT 1"; $data = mysql_query($strSQL); $row = mysql_fetch_array($data); return $row[0]; } function getPermNameFromID($permID) { $strSQL = "SELECT `permName` FROM `permissions` WHERE `ID` = " . floatval($permID) . " LIMIT 1"; $data = mysql_query($strSQL); $row = mysql_fetch_array($data); return $row[0]; } function getRoleNameFromID($roleID) { $strSQL = "SELECT `roleName` FROM `roles` WHERE `ID` = " . floatval($roleID) . " LIMIT 1"; $data = mysql_query($strSQL); $row = mysql_fetch_array($data); return $row[0]; } function getUsername($userID) { $strSQL = "SELECT `username` FROM `users` WHERE `ID` = " . floatval($userID) . " LIMIT 1"; $data = mysql_query($strSQL); $row = mysql_fetch_array($data); return $row[0]; } |
getUserRoles()
getUserRoles() возвратит массив ролевых имен, назначенных текущему пользователю. Во-первых, мы построим подходящий оператор SQL и выполним его. Пользуясь while(), мы построим из всех подходящих результатов цикл и, наконец, возвратим массив ID. Подобно этому, getAllRoles() возвратит все доступные ролевые имена (не только те, которые назначены пользователю). Основанный на значении аргумента, $format возвратит массив ID всем ролевым именам, или массив ассоциативной матрицы с ID и именем каждой роли. Это позволит нашей функции выполнить двойную нагрузку. Если мы хотим использовать массив пользовательских ролевых имен в MySQL, то нам нужен массив их ID; а если мы хотим показать ролевые имена на своей странице, было бы полезно иметь один массив со всей информацией.
buildACL
buildACL() генерирует для пользователя массив прав доступа, и это – основной компонент системы. Во-первых, убедимся, назначены ли пользователю какие-либо ролевые имена. Если да, используем array_merge(), чтобы скомбинировать существующий массив прав доступа с новым массивом, возвращенным с вызовом getRolePerms() (который получает все права доступа всех ролевых имен, которые назначены пользователю). Затем сделаем то же самое с индивидуальными правами доступа пользователя, вызывая на этот раз getUserPerms(). Важно прочесть права доступа пользователя вторыми, так как array_merge() перезаписывает ключи-дубликаты. Чтение прав доступа пользователя вторыми по счету гарантирует, что индивидуальные права доступа аннулируют любые права доступа, унаследованные от ролевых имен пользователя.
Все функции — getPermKeyFromID(), getPermNameFromID(), getRoleNameFromID() и getUsername() – являются просто «справочными» функциями. Они позволяют передать ID и возвратить соответствующее значение текста. Видно, что мы строим оператор SQL, затем выполняем его и возвращаем результат. Далее, добавим две функции, которые извлекут из базы данных права доступа.
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 |
function getRolePerms($role) { if (is_array($role)) { $roleSQL = "SELECT * FROM `role_perms` WHERE `roleID` IN (" . implode(",",$role) . ") ORDER BY `ID` ASC"; } else { $roleSQL = "SELECT * FROM `role_perms` WHERE `roleID` = " . floatval($role) . " ORDER BY `ID` ASC"; } $data = mysql_query($roleSQL); $perms = array(); while($row = mysql_fetch_assoc($data)) { $pK = strtolower($this->getPermKeyFromID($row['permID'])); if ($pK == '') { continue; } if ($row['value'] === '1') { $hP = true; } else { $hP = false; } $perms[$pK] = array('perm' => $pK,'inheritted' => true,'value' => $hP,'Name' => $this->getPermNameFromID($row['permID']),'ID' => $row['permID']); } return $perms; } function getUserPerms($userID) { $strSQL = "SELECT * FROM `user_perms` WHERE `userID` = " . floatval($userID) . " ORDER BY `addDate` ASC"; $data = mysql_query($strSQL); $perms = array(); while($row = mysql_fetch_assoc($data)) { $pK = strtolower($this->getPermKeyFromID($row['permID'])); if ($pK == '') { continue; } if ($row['value'] == '1') { $hP = true; } else { $hP = false; } $perms[$pK] = array('perm' => $pK,'inheritted' => false,'value' => $hP,'Name' => $this->getPermNameFromID($row['permID']),'ID' => $row['permID']); } return $perms; } function getAllPerms($format='ids') { $format = strtolower($format); $strSQL = "SELECT * FROM `permissions` ORDER BY `permName` ASC"; $data = mysql_query($strSQL); $resp = array(); while($row = mysql_fetch_assoc($data)) { if ($format == 'full') { $resp[$row['permKey']] = array('ID' => $row['ID'], 'Name' => $row['permName'], 'Key' => $row['permKey']); } else { $resp[] = $row['ID']; } } return $resp; } |
По существу, эти функции идентичны, за исключением таблиц, из которых они извлекают информацию. Единственный аргумент – это ID для ролевых имен/пользователей, которые нужно извлечь. Функция ролевых имен может быть передана массивом или целым числом, в то время как функция пользователя может быть передана только целым числом. Используя is_array(), мы определяем, как трактовать аргумент функции права доступа. Если это массив, мы используем implode() для создания списка, разделяемого запятой. В ином случае мы пользуемся этим значением в SQL. Затем создаем новый пустой массив с названием $perms – он будет хранить права доступа в определенном месте функции.
Внутри цикла while() мы выполняем несколько функций. Сначала генерируем переменную $pK, которую будем использовать в качестве названия ключа массива. Так как мы будем искать это значение, чтобы определить, имеет ли пользователь специальное право доступа, важно иметь его в постоянном формате, вот отчего мы пользуемся strtolower(). Если ключевое значение остается пустым, мы переходим к очередному повтору при помощи continue;. Далее, смотрим на $row[‘value’], чтобы установить неявное булево значение для права доступа. Это гарантирует, что только действительное значение «1» в таблице будет равно true (т.е. у пользователя есть право доступа), и важно для безопасности. Иначе мы устанавливаем право доступа на false. В конце функции создаем массив с несколькими поименованными ключами, так что можем получать всю информацию о праве доступа. Этот массив присваивается новому поименованному ключу в массиве $perms, который мы ранее создали. Обратите внимание, что мы пользуемся $pK для создания соответственно именованного указателя. Наконец возвращаем массив.
Видно, что в возвращенном массиве имеется название указателя «inherited» (унаследованный). Для ACL он имеет специальное значение. Если пользователь получает право доступа оттого, что оно принадлежит ролевому имени, которое ему назначено, о нем говорится как об унаследованном. Если права доступа назначаются пользователю вручную, они не наследуются.
В getAllPerms() мы сооружаем список всех доступных прав доступа. Подобно getAllRoles(), можно передать форматный аргумент для определения того, каким образом будут возвращены результаты. А теперь о последней части класса:
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 |
function userHasRole($roleID) { foreach($this->userRoles as $k => $v) { if (floatval($v) === floatval($roleID)) { return true; } } return false; } function hasPermission($permKey) { $permKey = strtolower($permKey); if (array_key_exists($permKey,$this->perms)) { if ($this->perms[$permKey]['value'] === '1' || $this->perms[$permKey]['value'] === true) { return true; } else { return false; } } else { return false; } } } ?> |
Последние два метода очень важны для функциональности ACL. userHasRole() принимает единственный аргумент ID ролевого имени. Двигаясь сквозь все элементы в массиве $userRoles, можно определить, определен ли этому ролевому имени пользователь. Если да, возвращаем true, если иначе — false. hasPermission() – это метод, используемый нами для определения, может ли пользователь получить доступ куда-либо. Передаем ключ для прав доступа, которые нужно проверить. Мы делаем их унифицированными, преобразовывая в нижний регистр, и смотрим, есть ли в массиве $perms указатель с таким именем. Если есть, убеждаемся, что он установлен на «1» и возвращает true, если наоборот – возвращаем false. Это та функция, которую мы используем, если захотим понять, может ли пользователь что-то сделать.
Шаг 4: пользователь Admin
В первой части своего раздела администрирования мы будем иметь дело с руководящими пользователями. Нам нужно создать четыре разных интерфейса для работы с областями ведущих пользователей: внесите их в список, чтобы было можно выбирать для редактирования, рассмотрев список пользователей в деталях, назначьте пользователям ролевые имена и предоставьте пользовательские права доступа.
Откройте /admin/users.php и добавьте следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php include("../assets/php/database.php"); include("../assets/php/class.acl.php"); $myACL = new ACL(); if ($myACL->hasPermission('access_admin') != true){ header("location: ../index.php");} ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="//www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>ACL Test</title> <link href="../assets/css/styles.css" rel="stylesheet" type="text/css" /> </head> <body> <div id="header"></div> <div id="adminButton"><a href="../">Main Screen</a> | <a href="index.php">Admin Home</a></div> <div id="page"> <!-- PAGE CONTENT --> </div> </body> </html> |
Как всегда, нам нужно включить свою базу данных и файлы ACL и установить объект ACL. Затем устанавливаем уровень безопасности страницы. В этом случае мы гарантируем, что у пользователя есть право доступа ‘access_admin’. Если нет, он перенаправляется.
ПРИМЕЧАНИЕ: если изменить права доступа ACL таким образом, что у пользователя № 1 не станет права доступа ‘access_admin’, вы не сможете войти на сторону админа. Также вы должны сначала зайти в /index.php до того, как посетить какую-либо из страниц админа, так как index.php устанавливает переменную сеанса, определяя вас как userID #1.
Сейчас это просто основная разметка страницы. В последующих шагах мы заменим вышеуказанный другим кодом, что позволит управлять пользователями. Мы употребим переменную строки запроса $action, чтобы определить, который из пользовательских интерфейсов нужно отобразить. Можем обратиться к четырем возможным значениям: если это нуль, мы отображаем список текущих пользователей. Если значение установлено на ‘user’, отображаем бланк отдельного пользователя. Если оно установлено на ‘roles’, мы отображаем бланк присвоения имен пользователю. Если установлено на ‘perms’, показываем бланк прав доступа, данных пользователю.
Пользователи списка:
Вставьте этот код в div с id ‘page’:
1 2 3 4 5 6 7 8 9 10 |
<? if ($_GET['action'] == '' ) { ?> <h2>Select a User to Manage:</h2> <? $strSQL = "SELECT * FROM `users` ORDER BY `Username` ASC"; $data = mysql_query($strSQL); while ($row = mysql_fetch_assoc($data)) { echo "<a href=\"?action=user&userID=" . $row['ID'] . "\">" . $row['username'] . "</a><br/ >"; } } ?> |
Идея довольно проста. Мы строим запрос SQL, запускаем его и просматриваем результаты. Для каждого пользователя генерируем ссылку, которая поможет редактировать этого конкретного пользователя.
Редактируем отдельного пользователя:
Теперь добавьте этот код прямо под предыдущим блоком программы:
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 |
<? if ($_GET['action'] == 'user' ) { $userACL = new ACL($_GET['userID']); ?> <h2>Managing <?= $myACL->getUsername($_GET['userID']); ?>:</h2> ... Some form to edit user info ... <h3>Roles for user: (<a href="users.php?action=roles&userID=<?= $_GET['userID']; ?>">Manage Roles</a>)</h3> <ul> <? $roles = $userACL->getUserRoles(); foreach ($roles as $k => $v) { echo "<li>" . $userACL->getRoleNameFromID($v) . "</li>"; } ?> </ul> <h3>Permissions for user: (<a href="users.php?action=perms&userID=<?= $_GET['userID']; ?>">Manage Permissions</a>)</h3> <ul> <? $perms = $userACL->perms; foreach ($perms as $k => $v) { if ($v['value'] === false) { continue; } echo "<li>" . $v['Name']; if ($v['inheritted']) { echo " (inheritted)"; } echo "</li>"; } ?> </ul> <? } ?> |
При редактировании пользователя нужно загрузить для него ACL. Это позволит видеть, какие у него есть ролевые имена и права доступа. Начинаем с создания нового объекта ACL и передачи $userID из строки запроса (таким образом мы загружаем ACL этого пользователя вместо зарегистрированного пользователя). Именно туда пойдет впоследствии ваша обычная форма редактирования пользователя. Текстовые поля для редактирования имени пользователя, пароля и пр. будут привычными. Пониже мы размещаем список ролевых имен, назначенных пользователю, а также обеспечиваем ссылку, так что можно будет назначать пользователю и другие ролевые имена. Строки 10-16 загружают все ролевые имена, назначенные пользователю и печатают их как элементы списка при помощи foreach(). Затем мы в едином стиле вносим в список права доступа пользователя. Печатаем только те права доступа, которые есть у пользователя, а не те, которые установлены на false.
Определение ролевых имен:
Бланк определения ролевых имен будет в итоге выглядеть таким образом:
Внесите этот код ниже предыдущего блока программы:
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 |
<? if ($_GET['action'] == 'roles') { ?> <h2>Manage User Roles: (<?= $myACL->getUsername($_GET['userID']); ?>)</h2> <form action="users.php" method="post"> <table border="0" cellpadding="5" cellspacing="0"> <tr><th></th><th>Member</th><th>Not Member</th></tr> <? $roleACL = new ACL($_GET['userID']); $roles = $roleACL->getAllRoles('full'); foreach ($roles as $k => $v) { echo "<tr><td><label>" . $v['Name'] . "</label></td>"; echo "<td><input type=\"radio\" name=\"role_" . $v['ID'] . "\" id=\"role_" . $v['ID'] . "_1\" value=\"1\""; if ($roleACL->userHasRole($v['ID'])) { echo " checked=\"checked\""; } echo " /></td>"; echo "<td><input type=\"radio\" name=\"role_" . $v['ID'] . "\" id=\"role_" . $v['ID'] . "_0\" value=\"0\""; if (!$roleACL->userHasRole($v['ID'])) { echo " checked=\"checked\""; } echo " /></td>"; echo "</tr>"; } ?> </table> <input type="hidden" name="action" value="saveRoles" /> <input type="hidden" name="userID" value="<?= $_GET['userID']; ?>" /> <input type="submit" name="Submit" value="Submit" /> </form> <form action="users.php" method="post"> <input type="button" name="Cancel" onclick="window.location='?action=user&userID=<?= $_GET['userID']; ?>'" value="Cancel" /> </form> <? } ?> |
Первое, что здесь нужно сделать – создать бланк и таблицу. В таблице будет три колонки: одна для ролевого имени, одна — для клетки с ответом участника и одна — для клетки с ответом не участника. После создания нового объекта ACL загружаем массив всех ролевых имен при помощи getAllRoles(). Это позволит нам показывать входные элементы каждого ролевого имени, а не только тех, которые определены пользователю.
Внутри цикла foreach() делаем следующее: начинаем новый ряд и печатаем метку с названием ролевого имени. Затем печатаем вход кнопки с зависимой фиксацией. Имя и id кнопок с зависимой фиксацией делаются уникальными для каждого ролевого имени при помощи формата “role_[roleID]” (т.е. role_0012). Строки 13 и 16 определяют, которую из кнопок следует проверить. Первая будет проверена, если пользователю уже назначена группа, в то время как вторая – если еще нет. Обратите внимание, что одна имеет значение «1» (для назначения), а другая – «0» (для не назначения). Затем заканчиваем ряд.
После всего этого добавляем некоторые скрытые элементы, которые говорят нам, что мы сохраняем и ID какого пользователя нужно сохранить. Затем добавляем клавиши submit (отправить) и cancel (отменить).
Назначаем права доступа:
Форма назначения прав доступа такая же, как бланк ролевых имен, но с различными входами, так что давайте добавим этот код:
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 |
<? if ($_GET['action'] == 'perms' ) { ?> <h2>Manage User Permissions: (<?= $myACL->getUsername($_GET['userID']); ?>)</h2> <form action="users.php" method="post"> <table border="0" cellpadding="5" cellspacing="0"> <tr><th></th><th></th></tr> <? $userACL = new ACL($_GET['userID']); $rPerms = $userACL->perms; $aPerms = $userACL->getAllPerms('full'); foreach ($aPerms as $k => $v) { echo "<tr><td>" . $v['Name'] . "</td>"; echo "<td><select name=\"perm_" . $v['ID'] . "\">"; echo "<option value=\"1\""; if ($rPerms[$v['Key']]['value'] === true && $rPerms[$v['Key']]['inheritted'] != true) { echo " selected=\"selected\""; } echo ">Allow</option>"; echo "<option value=\"0\""; if ($rPerms[$v['Key']]['value'] === false && $rPerms[$v['Key']]['inheritted'] != true) { echo " selected=\"selected\""; } echo ">Deny</option>"; echo "<option value=\"x\""; if ($rPerms[$v['Key']]['inheritted'] == true || !array_key_exists($v['Key'],$rPerms)) { echo " selected=\"selected\""; if ($rPerms[$v['Key']]['value'] === true ) { $iVal = '(Allow)'; } else { $iVal = '(Deny)'; } } echo ">Inherit $iVal</option>"; echo "</select></td></tr>"; } ?> </table> <input type="hidden" name="action" value="savePerms" /> <input type="hidden" name="userID" value="<?= $_GET['userID']; ?>" /> <input type="submit" name="Submit" value="Submit" /> <input type="button" name="Cancel" onclick="window.location='?action=user&userID=<?= $_GET['userID']; ?>'" value="Cancel" /> </form> <? } ?> |
Как в случае с бланками ролевых имен, начинаем с добавления формы и таблицы, на этот раз с двумя колонками. Затем создаем объект ACL, извлекаем массив прав доступа (строка 8) и получаем массив всех прав доступа (строка 9). В цикле foreach() печатаем новый ряд и название права доступа. Затем запускаем элемент select (отметить, выбрать). У входа select будет три варианта выбора: Allow (разрешить), Deny (отказать) и Inherit (унаследовать). Смотрим на значение $rPerms[$v[‘Key’]][‘value’], чтобы определить, какой из вариантов выбрать. Allow или Deny не будут выбраны благодаря $rPerms[$v[‘Key’]][‘inheritted’] != true, если значение прав доступа унаследовано. Если право доступа унаследовано, будет выбран вариант Inherited.
Строка 23-32 совершенствует вариант inherit. Если право доступа унаследовано, она делает его выбранным. Затем определяет значение унаследованного права доступа и устанавливает переменную $iVal таким образом, что мы можем использовать текстовое значение в метке опции в строке 33. После окончания работы над входом select и таблицей добавляем скрытые входы для установления опций сохранения и добавляем кнопки submit и cancel.
Когда код запущен, все оканчивается рядом для каждого имеющегося права доступа и просмотром, показывающим, есть ли оно у пользователя.
Сохранение данных:
Добавьте этот код в /admin/users.php прямо над тэгом типа документа:
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 |
<? if (isset($_POST['action'])) { switch($_POST['action']) { case 'saveRoles': $redir = "?action=user&userID=" . $_POST['userID']; foreach ($_POST as $k => $v) { if (substr($k,0,5) == "role_") { $roleID = str_replace("role_","",$k); if ($v == '0' || $v == 'x') { $strSQL = sprintf("DELETE FROM `user_roles` WHERE `userID` = %u AND `roleID` = %u",$_POST['userID'],$roleID); } else { $strSQL = sprintf("REPLACE INTO `user_roles` SET `userID` = %u, `roleID` = %u, `addDate` = '%s'",$_POST['userID'],$roleID,date ("Y-m-d H:i:s")); } mysql_query($strSQL); } } break; case 'savePerms': $redir = "?action=user&userID=" . $_POST['userID']; foreach ($_POST as $k => $v) { if (substr($k,0,5) == "perm_") { $permID = str_replace("perm_","",$k); if ($v == 'x') { $strSQL = sprintf("DELETE FROM `user_perms` WHERE `userID` = %u AND `permID` = %u",$_POST['userID'],$permID); } else { $strSQL = sprintf("REPLACE INTO `user_perms` SET `userID` = %u, `permID` = %u, `value` = %u, `addDate` = '%s'",$_POST['userID'],$permID,$v,date ("Y-m-d H:i:s")); } mysql_query($strSQL); } } break; } header("location: users.php" . $redir); } ?> |
Этот код сначала проверяет, было ли что-то назначено, путем просмотра $_POST[‘action’]. Это – значение, которое содержалось в одном из элементов скрытой формы тех двух бланков, которые мы сделали.
Если мы назначили только бланк ролевых имен, происходит следующее:
Мы строим строку запросов $redir, к которой будем отосланы после обработки бланка.
Просматриваем цикл из всех переменных $_POST.
При помощи substr() ищем, являются ли первые 5 символов имени переменной “role_”. Таким образом мы получаем входы прав доступа для следующих шагов.
Если значение текущего входа равно «0» или «х» (т.е. нам не нужно, чтобы у пользователя было это ролевое имя), выполняем удаление запроса. Если удалить ролевое имя пользователя из таблицы user_roles, то ему это ролевое имя больше не назначено.
Если значения не «0» или «х» (строка 14), выполняем замену запроса.
Для любого запроса используем sprintf() в целях обеспечения безопасности (sprintf() запускает ввод переменных и помогает защитить информацию от атак на SQL).
Запускаем SQL при помощи mysql_query().
Обратите внимание на замену запроса: синтаксис замены – это специальный синтаксис MySQL, позволяющий плавное обновление или вставку. Используя замену, можно избавиться от написания большого количества кода PHP. Делая таблицу user_roles мы создали уникальный указатель в полях userID и roleID. При запуске оператора ‘replace into’ он сначала смотрит в таблице, создаст ли внесение нового ряда копию (т.е. ряд с теми же значениями указателя уже существует). Если существует ряд, который соответствует указателям, оператор дополняет этот ряд. Если нет, он вставляет новый ряд.
Если мы просто отправили бланк прав доступа, происходит то же самое, за исключением того, что происходит поиск отличающейся приставки в названии входа, а также используется другая таблица базы данных. Как только произведены какие-либо действия, используем header(«location:…») для перенаправления обратно на ту страницу, на которой мы уже были, и присоединяем готовую переменную строки запроса $redir.
Шаг 5: ролевые имена администратора
Теперь, когда закончена работа над бланками управления пользователями, нужно управлять своими ролевыми именами. Чтобы было попроще, следует сделать всего два действия: просмотреть список ролевых имен или отредактировать ролевое имя. Создайте /admin/roles.php при помощи следующего кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php include("../assets/php/database.php"); include("../assets/php/class.acl.php"); $myACL = new ACL(); if ($myACL->hasPermission('access_admin') != true){ header("location: ../index.php");} ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="//www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>ACL Test</title> <link href="../assets/css/styles.css" rel="stylesheet" type="text/css" /> </head> <body> <div id="header"></div> <div id="adminButton"><a href="../">Main Screen</a> | <a href="index.php">Admin Home</a></div> <div id="page"> <!-- PAGE CONTENT --> </div> </body> </html> |
Составляем список ролевых имен:
Так же, как на пользовательской странице, мы начинаем с включений, создавая объект ACL, и с формата страницы. Наше действие по умолчанию (страница загружена без строки запроса) – составить список доступных ролевых имен, поэтому вставьте данный код в :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<? if ($_GET['action'] == '') { ?> <h2>Select a Role to Manage:</h2> <? $roles = $myACL->getAllRoles('full'); foreach ($roles as $k => $v) { echo "<a href=\"?action=role&roleID=" . $v['ID'] . "\">" . $v['Name'] . "</a><br/ >"; } if (count($roles) < 1) { echo "No roles yet.<br/ >"; } ?> <input type="button" name="New" value="New Role" onclick="window.location='?action=role'" /> <? } ?> |
Сначала проверяем, пуста ли переменная строки запроса. Затем сохраняем список всех доступных ролевых имен в $roles при помощи getAllRoles(). При каждом повторении цикла foreach() делаем ссылку, которая приведет нас к форме редактирования каждого ролевого имени в отдельности. Если в массиве $roles нет ролевых имен, показываем доброжелательное послание. Наконец, добавляем кнопку, которая позволит нам добавить новое ролевое имя.
Редактируем ролевое имя:
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 |
<? if ($_GET['action'] == 'role') { if ($_GET['roleID'] == '') { ?> <h2>New Role:</h2> <? } else { ?> <h2>Manage Role: (<?= $myACL->getRoleNameFromID($_GET['roleID']); ?>)</h2><? } ?> <form action="roles.php" method="post"> <label for="roleName">Name:</label><input type="text" name="roleName" id="roleName" value="<?= $myACL->getRoleNameFromID($_GET['roleID']); ?>" /> <table border="0" cellpadding="5" cellspacing="0"> <tr><th></th><th>Allow</th><th>Deny</th><th>Ignore</th></tr> <? $rPerms = $myACL->getRolePerms($_GET['roleID']); $aPerms = $myACL->getAllPerms('full'); foreach ($aPerms as $k => $v) { echo "<tr><td><label>" . $v['Name'] . "</label></td>"; echo "<td><input type=\"radio\" name=\"perm_" . $v['ID'] . "\" id=\"perm_" . $v['ID'] . "_1\" value=\"1\""; if ($rPerms[$v['Key']]['value'] === true && $_GET['roleID'] != '') { echo " checked=\"checked\""; } echo " /></td>"; echo "<td><input type=\"radio\" name=\"perm_" . $v['ID'] . "\" id=\"perm_" . $v['ID'] . "_0\" value=\"0\""; if ($rPerms[$v['Key']]['value'] != true && $_GET['roleID'] != '') { echo " checked=\"checked\""; } echo " /></td>"; echo "<td><input type=\"radio\" name=\"perm_" . $v['ID'] . "\" id=\"perm_" . $v['ID'] . "_X\" value=\"X\""; if ($_GET['roleID'] == '' || !array_key_exists($v['Key'],$rPerms)) { echo " checked=\"checked\""; } echo " /></td>"; echo "</tr>"; } ?> </table> <input type="hidden" name="action" value="saveRole" /> <input type="hidden" name="roleID" value="<?= $_GET['roleID']; ?>" /> <input type="submit" name="Submit" value="Submit" /> </form> <form action="roles.php" method="post"> <input type="hidden" name="action" value="delRole" /> <input type="hidden" name="roleID" value="<?= $_GET['roleID']; ?>" /> <input type="submit" name="Delete" value="Delete" /> </form> <form action="roles.php" method="post"> <input type="submit" name="Cancel" value="Cancel" /> </form> <? } ?> |
После проверки, находится ли там переменная строки запроса, смотрим, была ли передана в строку запроса roleID. Если была, предполагаем, что мы редактируем ролевое имя, если нет – создаем его (отображаем заголовок как положено). Затем создаем бланк. Внутри него нам нужен текстовый вход для имени роли и таблица, содержащая права доступа. В таблице есть колонки для названия права доступа, а также allow (разрешить), deny (запретить) и ignore (игнорировать). Как и во время редактирования прав доступа пользователей, нам нужно просмотреть массив всех прав доступа (строка 15, $myACL->getAllPerms(‘full’)).
В каждом ряду печатаем название права доступа и три кнопки с зависимой фиксацией. Они используют ту же самую систему обозначений, что и пользовательская форма («perm_[permID]»). «Allow» (разрешить) или «Deny» (запретить) выбраны в зависимости от значения сохраненного права доступа (благодаря строкам 19 и 22). Если выбрать «ignore» (игнорировать), для сочетания этих ролевого имени/права доступа не сохраняется никакого значения. Обратите внимание, что первые два блока if() содержат в себе && $_GET[‘roleID’] != ”. Это гарантирует, что если не передано никакого ID пользователя (что мы создаем новое ролевое имя), то «ignore» выбирается по умолчанию. Затем добавляем скрытые входы для установки настроек сохранения и закрываем бланк. Таким же образом добавляем другой бланк со скрытыми входами, чтобы удалить ролевое имя, и еще один бланк с кнопкой отмены «cancel», которая будет возвращать нас на страницу ролевых имен. Если все идет по плану, при попытке редактирования прав доступа для ролевого имени мы должны получить следующее:
Сохранение данных:
Вставьте этот код в /admin/roles.php прямо перед тэгом типа документа:
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 |
<? if (isset($_POST['action'])) { switch($_POST['action']) { case 'saveRole': $strSQL = sprintf("REPLACE INTO `roles` SET `ID` = %u, `roleName` = '%s'",$_POST['roleID'],$_POST['roleName']); mysql_query($strSQL); if (mysql_affected_rows() > 1) { $roleID = $_POST['roleID']; } else { $roleID = mysql_insert_id(); } foreach ($_POST as $k => $v) { if (substr($k,0,5) == "perm_") { $permID = str_replace("perm_","",$k); if ($v == 'X') { $strSQL = sprintf("DELETE FROM `role_perms` WHERE `roleID` = %u AND `permID` = %u",$roleID,$permID); mysql_query($strSQL); continue; } $strSQL = sprintf("REPLACE INTO `role_perms` SET `roleID` = %u, `permID` = %u, `value` = %u, `addDate` = '%s'",$roleID,$permID,$v,date ("Y-m-d H:i:s")); mysql_query($strSQL); } } header("location: roles.php"); break; case 'delRole': $strSQL = sprintf("DELETE FROM `roles` WHERE `ID` = %u LIMIT 1",$_POST['roleID']); mysql_query($strSQL); $strSQL = sprintf("DELETE FROM `user_roles` WHERE `roleID` = %u",$_POST['roleID']); mysql_query($strSQL); $strSQL = sprintf("DELETE FROM `role_perms` WHERE `roleID` = %u",$_POST['roleID']); mysql_query($strSQL); header("location: roles.php"); break; } } ?> |
Аналогично пользовательской странице проверяем, было ли что-то отправлено через $_POST и каково было значение $_POST[‘action’]. Если бы мы сохраняли ролевое имя, то сделали бы следующее:
Замену запроса в таблице ролевых имен. Она обновит/добавит ролевое имя. Строки 8-13 выполняют важную функцию в сохранении ролевых имен. Если делать обновление, то у нас уже есть ID для этого ролевого имени. Однако если нужно его вставить, то ID ролевого имени мы не знаем. При выполнении замены запроса возвращается количество задействованных рядов. Если их количество было больше одного, ряд обновляется, так что нам нужно использовать id ролевого имени из бланка. Если было задействовано не более одного ряда, он вставляется, а мы пользуемся mysql_insert_id() для получения ID последнего вставленного ряда.
Затем просматриваем переменные $_POST, и строка 16 гарантирует, что нами выполняются ряды, где название входа начинается с «perm_».
Строка 18 получает floatval() права доступа, таким образом, в итоге мы имеем только целое значение ID «perm» (так мы узнаем, с каким из прав доступа мы сейчас имеем дело).
if ($v == ‘x’) {…} запустится, если в бланке выбрать для права доступа «Ignore». Она попытается удалить ряд из таблицы, в котором верные ID ряда и ID права доступа. Если это случится, мы используем continue; для перехода к следующей переменной.
Если мы добрались до этого момента, предполагаем, что нужно добавить или обновить право доступа для этого ролевого имени. Так, мы используем синтаксис «replace into», который использовали в форме пользователя. Важно иметь в нем roleID и permID, чтобы база данных могла корректировать существующий ряд.
Наконец, запускаем SQL и переходим на страницу ролевых имен.
Если мы отправляем форму удаления, то удаляем ролевое имя из таблицы ролевых имен. Затем таким же образом удаляем любые записи из таблиц user_roles и role_perms, которые совпадают с ID ролевого имени, так что нам не придется в итоге иметь дело с пользователями и правами доступа, назначенными несуществующим ролевым именам. Теперь переходим к странице ролевых имен.
Шаг 6: права доступа администратора
Как у ролевых имен администратора, так и у его прав доступа имеется две функции: составить список имеющихся прав доступа и редактировать их. Начнем с этого кода в /admin/perms.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php include("../assets/php/database.php"); include("../assets/php/class.acl.php"); $myACL = new ACL(); if ($myACL->hasPermission('access_admin') != true){ header("location: ../index.php");} ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="//www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>ACL Test</title> <link href="../assets/css/styles.css" rel="stylesheet" type="text/css" /> </head> <body> <div id="header"></div> <div id="adminButton"><a href="../">Main Screen</a> | <a href="index.php">Admin Home</a></div> <div id="page"> <!-- PAGE CONTENT --> </div> </body> </html> |
Составляем список прав доступа:
Поместите этот код в div’е страницы (на месте ):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<? if ($_GET['action'] == '') { ?> <h2>Select a Permission to Manage:</h2> <? $roles = $myACL->getAllPerms('full'); foreach ($roles as $k => $v) { echo "<a href=\"?action=perm&permID=" . $v['ID'] . "\">" . $v['Name'] . "</a><br />"; } if (count($roles) < 1) { echo "No permissions yet.<br />"; } ?> <input type="button" name="New" value="New Permission" onclick="window.location='?action=perm'" /> <? } ?> |
Сначала используем getAllPerms() для получения массива всех прав доступа. Затем просмотрим их все для построения своего списка. Каждое повторение цикла foreach() сформирует ссылку, которая будет направлять нас на страницу для редактирования данного права доступа. Если прав доступа в наличие нет, мы показываем это сообщением и заканчиваем форму кнопкой «New Permission» (новое право доступа).
Вот результат:
Редактируем право доступа:
Чтобы редактировать/добавить индивидуальное право доступа, нужно вставить этот код прямо за предыдущим блоком:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<? if ($_GET['action'] == 'perm') { if ($_GET['permID'] == '') { ?> <h2>New Permission:</h2> <? } else { ?> <h2>Manage Permission: (<?= $myACL->getPermNameFromID($_GET['permID']); ?>)</h2><? } ?> <form action="perms.php" method="post"> <label for="permName">Name:</label><input type="text" name="permName" id="permName" value="<?= $myACL->getPermNameFromID($_GET['permID']); ?>" maxlength="30" /><br /> <label for="permKey">Key:</label><input type="text" name="permKey" id="permKey" value="<?= $myACL->getPermKeyFromID($_GET['permID']); ?>" maxlength="30" /><br /> <input type="hidden" name="action" value="savePerm" /> <input type="hidden" name="permID" value="<?= $_GET['permID']; ?>" /> <input type="submit" name="Submit" value="Submit" /> </form> <form action="perms.php" method="post"> <input type="hidden" name="action" value="delPerm" /> <input type="hidden" name="permID" value="<?= $_GET['permID']; ?>" /> <input type="submit" name="Delete" value="Delete" /> </form> <form action="perms.php" method="post"> <input type="submit" name="Cancel" value="Cancel" /> </form> <? } ?> |
Как в бланках ролевых имен, проверяем, предусмотрен ли в строке запроса ID права доступа и отображаем дополнение, либо обновляем основанный на нем заголовок. Открываем тэг формы и добавляем два текстовых входа: один для названия права доступа, второй для ключа права доступа. Название появится в бланках, в то время как ключ – это то, что нами использовалось в скриптах. Ключ должен сильно напоминать название, за исключением того, что в нем не должно быть пробелов или символов, и должен использоваться нижний регистр. Оба текстовых поля мы снабдим значениями по умолчанию на случай обновлений.
В конце формы добавляем скрытые входы и кнопку «submit» (отправить). Затем делаем бланки «delete» (удалить) и «cancel» (отменить).
Сохранение данных:
Наконец нам нужно сохранить бланк прав доступа, так что добавьте этот код наверх /admin/perms.php прямо над типом документа.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if (isset($_POST['action'])) { switch($_POST['action']) { case 'savePerm': $strSQL = sprintf("REPLACE INTO `permissions` SET `ID` = %u, `permName` = '%s', `permKey` = '%s'",$_POST['permID'],$_POST['permName'],$_POST['permKey']); mysql_query($strSQL); break; case 'delPerm': $strSQL = sprintf("DELETE FROM `permissions` WHERE `ID` = %u LIMIT 1",$_POST['permID']); mysql_query($strSQL); break; } header("location: perms.php"); } |
Как во всех прочих скриптах прав доступа, нам нужно выяснить, какое действие было отправлено. Если мы сохраняем право доступа, то выполняем над действием замену. Она либо обновит, либо вставит соответствие. Если мы отправили форму удаления, то выполняем запрос на удаление. В ином случае, нас перенаправят на perms.php.
Шаг 7: ядро администратора
Нам необходима начальная точка ACL admin. Просто создадим нечто простое с ссылками на три страницы. Вот превью (предварительный просмотр) и код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?php include("../assets/php/database.php"); include("../assets/php/class.acl.php"); $myACL = new ACL(); if ($myACL->hasPermission('access_admin') != true){ header("location: ../index.php");} ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="//www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>ACL Test</title> <link href="../assets/css/styles.css" rel="stylesheet" type="text/css" /> </head> <body> <div id="header"></div> <div id="adminButton"><a href="../">Main Screen</a></div> <div id="page"> <h2>Select an Admin Function:</h2> <a href="users.php">Manage Users</a><br /> <a href="roles.php">Manage Roles</a><br /> <a href="perms.php">Manage Permissions</a><br /> </div> </body> </html> |
Все довольно ясно — у нас три ссылки для управления тремя различными аспектами своего ACL.
Шаг 8: запуск ACL на вашем сайте
Применить новую систему ACL на своем сайте довольно просто. Каждая страница, которую нужно защитить, должна иметь базу данных и файл ACL, вставленный вверху. После того нужно создать новый экземпляр объекта ACL.
Например, у вас установлено право доступа с ключом «access_admin» и вы хотели бы использовать его, чтобы контролировать доступ к интерфейсу админа. Вверху страницы можно было бы использовать для проверки этот скрипт:
1 2 3 4 5 6 7 8 9 |
<?php include("assets/php/database.php"); include("assets/php/class.acl.php"); $myACL = new ACL(); if ($myACL->hasPermission('access_admin') != true) { header("location: insufficientPermission.php"); } ?> |
Видите, мы создали объект ACL. Так как мы не передаем ID пользователя в качестве аргумента, система прочтет переменную сеанса $_SESSION[‘userID’]. Затем используем $myACL->hasPermission(‘access_admin’) для проверки, есть ли у пользователя это право доступа. Если нет, он перенаправляется на insufficientPermission.php. Таким образом, он не может войти в защищенные области, в которые не имеет права доступа.
В предоставленном исходном файле я предусмотрел файл указателя, который обеспечивает простое тестирование ACL, основанное на вышеприведенном примере кода. Образец указателя демонстрирует список всех прав доступа и иконки, показывающие, может ли данный пользователь получить к каждому из них доступ. Также тут имеется список пользователей, который позволяет заменить пользователя, для чего и показывается ACL. Вот код для образца указателя:
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 |
<?php include("assets/php/database.php"); include("assets/php/class.acl.php"); $userID = $_GET['userID']; $_SESSION['userID'] = 1; $myACL = new ACL(); ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="//www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>ACL Test</title> <link href="assets/css/styles.css" rel="stylesheet" type="text/css" /> </head> <body> <div id="header"></div> <div id="adminButton"><a href="admin/">Admin Screen</a></div> <div id="page"> <h2>Permissions for <?= $myACL->getUsername($userID); ?>:</h2> <? $userACL = new ACL($userID); $aPerms = $userACL->getAllPerms('full'); foreach ($aPerms as $k => $v) { echo "<strong>" . $v['Name'] . ": </strong>"; echo "<img src=\"assets/img/"; if ($userACL->hasPermission($v['Key']) === true) { echo "allow.png"; $pVal = "Allow"; } else { echo "deny.png"; $pVal = "Deny"; } echo "\" width=\"16\" height=\"16\" alt=\"$pVal\" /><br />"; } ?> <h3>Change User:</h3> <? $strSQL = "SELECT * FROM `users` ORDER BY `Username` ASC"; $data = mysql_query($strSQL); while ($row = mysql_fetch_assoc($data)) { echo "<a href=\"?userID=" . $row['ID'] . "\">" . $row['username'] . "</a><br />"; } ?> </div> </body> </html> |
Заключительные мысли
Будучи скомбинированной с хорошей платформой управления пользователями, система ACL – прекрасный способ защитить свой веб-сайт. Следуя этим шагам, вы сможете создать свою собственную гибкую систему безопасности. Данная система администрирования является хорошим примером того, что можно создать, если не имеется заранее установленной системы админа. Она показывает все правила, нужные для эффективного управления своей ACL. С другой стороны, если вы уже создали свою собственную систему управления доступом, будет довольно легко взять на вооружение эти техники и применить их в своем проекте.
Надеюсь, урок по созданию списка контроля доступа для сайта, вам понравился.
Автор: Andrew Steenbuck
Перевод и редакция: Рог Виктор и Андрей Бернацкий. Команда webformyself.
Источник: //net.tutsplus.com
E-mail: contact@webformyself.com
Проект webformyself.com — Как создать свой сайт. Основы самостоятельного сайтостроения
"Киберсант-вебмастер" — самый полный курс по сайтостроению в рунете!
P.S. Хотите опубликовать интересный тематический материал и заработать? Если ответ «Да», то жмите сюда.
Комментарии (4)