Реализация механизма разграничения прав доступа к админ-части
На своей практике веб-разработки я очень часто сталкивался с ситуациями, в
которых заказчики ставили конкретную цель, а именно о разделении частей админки
относительно доступности тем или иным пользователям. При этом разработка данного
модуля велась в контексте расширяемой системы, а то есть с нефиксированым числом
модулей, к которым организовуется доступ, ну и, соответственно, неограниченным
числом пользователей системы.
Что ж, сама по себе данная тема довольно грузная, и требует определённого
времени на анализ и постанувку задачи.
В контексте данной статьи, мы будем вести разработку в контексте некоторой
абстрактной информационной системы, со своей инфраструктурой и архитектурой, при
этом данная система предоставляет пользователю возможность расширять функционал,
а то есть устанавливать новые модули, и соответственно устанавливать права
доступа к ним тому либо иному пользователю, зарегистрированному в качестве
администратора системы.
Давайте с самого начала обсудим архитектуру модульной системы на выбранной нами
псевдо-системе.
Все модули представлены ввиде подключаемых к главному документу (индекс-файлу)
вставок. Запрос модуля происходит из строки запроса QUERY_STRING, и название
подключаемого модуля передаётся в качестве аргумента act. В некотором месте
индекса файла происходит изъятие и обработка данного параметра. После, если у
пользователя достаточно прав для доступа к модулю в контексте чтения, происходит
проверка существования указанного в строке запроса модуля, и если таковой
существует, то происходит его подключение к индекс файлу.
Я не просто так упомянул о "контексте чтения", так как наша системе предполагает
существование двух контекстов работы с системой, а именно - чтение и запись. При
этом под чтением предполагается непосредственный доступ к модулю и к тем его
частям, которые не предполагают внесение изменений в структуру данных в БД. Под
записью же предполагается непосредственное внесение изменений в информацию,
хранимую в базе данных.
Для воплощения данного механизма мы будет проверять значение переменной строки
запроса `do`, которая обрабатывается в самом модуле и носит информацию о том, к
какому разделу модуля необходимо предоставить доступ пользовалю.
Значение do буду фиксированными, данная переменная будет принимать следующие
значения:
* main - главная часть модуля (доступно в контексте чтения)
* config - раздел настройки модуля (доступно в контексте записи)
* create - произвести некоторые действия, по добавлению информации в БД
(доступно в контексте записи)
* delete - доступ к разделу, предоставляющему возможности удалить некоторую
информацию, в контексте данного модуля (доступно в контексте записи)
* edit - доступ к редактированию информации в контексте модуля (доступно в
контексте записи)
В целом, этот список можно увеличить, при этом всё зависит лишь только от
масштабов проекта и его потребностей в функционале.
Теперь непосредственно о модулях. Кроме физического существования некоторого
модуля в контексте файловой системы проекта, модуль так же должен быть добавлен
в особую таблицу БД, которая будет содержать информацию о всех существующих
модулях в системе. Добавление и изменение данных данной таблицы, обычно,
производится непосредственно в контексте модулей, а то есть во время их
инсталяции в системе. Однако это уже углубление в принципы посмотроения
расширяемых систем, о чём мы как-то в другой раз поговорим, и посему, мы
ограничимся ручным обновлением и добавлением данных о модулях.
Так, запись о модуле системы будет содержать следующую информацию: английский
идентификатор названия модуля, который будет идентичен значению переменной среды
GET - act (относительно него будет производится непосредственно запрос модуля),
русский идентификатор модуля, который будет использоватся в списке модулей.
Кроме модулей у нас будут ещё две таблицы, а именно таблица в которой будут
хранится данные относительно профилей прав доступа и таблица с информацией о
пользователях непосредственно.
Таблица профилей безопасности будет состоять всего из трёх полей - идентификатор
профиля (числовое значение идентификатора записи), текстый идентификатор модуля
(предназначенный для пользователей), а так же особым образом сформированная
текстовая метка, содержащая информацию о правах пользователя, в контексте
каждого из модулей.
Что ж, давайте рассмотрим эту особую структуру. Она будет следующей: [
module_indefier : [0 | 1]+ : [0 | 1]+ ;] *
То есть идёт список из пар: имя модуля ":" права чтения "," права записи ";".
При этом данная метка обновляется в момент внесения изменений о правах доступа
пользователя к системе. Если в системе появляется информация о модуле, который
не вошёл в данную метку, то стоит просто произвести процедуру редактирования, и
данные сохранятся автоматически.
Теперь же нам осталось рассмотреть структуру всего одной таблицы БД, и мы сможем
принятся за реализацию алгоритмической части, а именно таблицы с информацией о
пользователях системы, ведь назначение им прав доступа и является нашей главной
задачей.
Я не буду добавлять ничего лишнего в неё, но лишь то, что будет использоватся в
контексте темы данной статьи. Таблица пользователей будет содержать следующие
поля: идентифицатор пользователя (числовой счётчик), логин, пароль (хеш
оригинального пароля), профиль безопасности пользователя (идетификатор группы
пользователя, относительно прав в системе), и всё. Мне кажется этой информации
нам с вами вполне хватит, для реализации поставленной задачи, а уже все
остальные надстройки я предоставляю возможность сделать самим.
Итак, структуру мы обсудили, и, надеюсь, у всех сложилось уже некоторое
представление о том, как мы будем реализовывать поставленную в теме статьи
задачу. Сейчас я приведу вспомогательный SQL-код таблиц, описанных выше, после
чего сразу же перейду к воплощению алгоритма проверки прав доступа пользователя,
а так же создания и изменения профилей доступа. После каждого отдельного модуля
мы подробно обсудим все вопросы, которые могут возникнуть у читателей.
Таблица `modules`:
CREATE TABLE `modules` (
`id` bigint(20) NOT NULL auto_increment,
`indefier` text collate utf8_unicode_ci NOT NULL,
`title` text collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1
DEFAULT CHARSET=utf8
COLLATE=utf8_unicode_ci;
Таблица `secure_groups`:
CREATE TABLE `secure_groups` (
`id` bigint(20) NOT NULL auto_increment,
`title` text collate utf8_unicode_ci NOT NULL,
`perms` text collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1
DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
Таблица `users`
CREATE TABLE `users` (
`id` bigint(20) NOT NULL auto_increment,
`login` text collate utf8_unicode_ci NOT NULL,
`passwd` text collate utf8_unicode_ci NOT NULL,
`groupId` int(1) NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1
DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
Далее описан класс для внедрения функций проверки прав доступа пользователей к
модулям системы.
<?php
class security extends engine{
var $temp=array();
function getUserId(){
$hash=explode('::',$_COOKIE['site_hash']);
$id=$hash[0];
return $id;
}
Данный класс внедряет функции, предназначенные для воплещения алгоритмического
задания, описанного выше. Сейчас мы обсудим каждую функцию отдельно.
Функция secure::getUserId()
Используя данную функцию, мы подразумеваем, что во время авторизации
пользователя в системе в переменной среде $_COOKIE была установлена переменная `site_hash`,
состоящая из идентификатора пользователя в системе и хеша для проверки
аутентичности его в системе. Функция просто изымает значение идентификатора,
возращая его значение на выходе.
Функция secure::getUserSecurityAccess($id)
На выходе данная функция возвращает идентификатор профиля безопасности текущего
пользователя в системе.
Функция secure::checkUserPermission($module,$act))
Производится запрос к БД, относительно прав пользователя на произведение
действий чтения/записи в контексте переданного в качестве параметра модуля.
Осталось лишь описать процедуру формирования переменной в среде $_COOKIE, и тему
статьи можно будет считать расскрытой.
Процедура авторизации будет выглядеть ввиде внесения личных данных пользователя
(логин и пароль) в специальную форму, после отправки которой произойдёт
обработка данных, переданных пользователем, по-методу функции checkAuthData(),
и, в случае корректности данных, будет произведено сохранение данных о
пользователе ввиде куки записи на период установленный пользователем, либо в
отсутствии заданного значение на период по-умолчанию.
Для проверки аутентичности данных хранимых в переменной среде $_COOKIE, мы будем
использовать функцию EatCookie(), которая будет производить валидацию данных,
возвращая булевый результат проверки (истина - ложь).
Я не привожу форму для отправки, так как это не часть теории программирования,
указав лишь идентификаторы полей.
* `ulogin` - логин пользователя
* `upasswd` - пароль пользователя
* `stime` - время сессии, устанавливаемое пользователем (от 1 до 5 часов)
* `auth` - имя кнопки отправки
При разработке CMS S.Builder наша команда
активно использовала AJAX. Теперь вот решили поделиться накопленным
опытом. Начнем с этого хабратопика. Не буду здесь затрагивать различные
фреймворки и библиотеки. Свой код всегда роднее. Для работы с AJAX-ом в
S.Builder написана библиотека
sbAJAX. Можете качать и пользоваться :). В этом файле есть функция
sbEvalJS. Для тех, кто не знает, объясню. При подгрузке через AJAX и вставке
на страницу HTML-кода, содержащего JavaScript, JavaScript выполняться не будет
или полезут баги. Эта функция как раз решает поставленную задачу.
Хотя наш обзор немного запоздал, оригинальный Dojo 1.2 вышел в релизной
версии ещё 6-го октября, но сейчас мы наверстаем упущенное. И так, Dojo Toolkit — это самая мощная и
гибкая ajax-библиотека из всех, что есть на рынке, она активно развивается и
имеет большое комьюнити. Кстати, это самое комьюнити, совместно с компанией
Sitepen, имеет ещё несколько проектов, среди которых и Cometd и некоторые
другие, не менее интересные, о которых мы скоро вам расскажем. Сегодня же все
внимание на флагманский продукт —
Dojo
1.2.
Если вы профессиональный веб-разработчик и постоянно имеете дело с
разработкой и отладкой сложных AJAX приложений, то наверняка знаете и
используете Firebug — плагин для браузера
Firefox, предназначенный для отладки и исследования веб-приложений. Текущая его
версия, 1.2х достаточно стабильная и функциональна, чтобы помочь в 99% проблем,
которые могут возникнуть при разработке. Но и этот инструмент не лишён если не
недостатков, то некоторых фич, которые могли бы облегчить работу. И даже
идеальный инструмент можно сделать ещё более идеальным, как бы это не звучало.