А это клавиатура, с помощью которой я творю...
http://kurepin.ru/php/slang.ru/12/
Rambler's Top100
Строим сайт slang.ru, глава 12

Строим сайт slang.ru

Глава 12. user_access()

На очереди у нас user_access(). Прежде чем писать эту функцию, давайте хорошенько поразмыслим над ее задачами.

Логическая цепочка проверки уровня доступа к словарю мне видится так: сначала смотрим на user_id. Если он равен нулю, то это обращение незарегистрированного пользователя. В этом случае нам надо проверить только общий доступ к словарю и выдать результат. Если же user_id задан, то необходимо сложить общедоступные права к словарю с правами для указанного пользователя. После этого надо проверить уровень доступа и вернуть разрешение или запрет.

А как и где мы опишем права доступа для незарегистрированных пользователей - простых посетителей нашего проекта? Я вижу два варианта: первый - размещать в таблице tbl_user_dic запись с ud_user равным 0, где 0 - все пользователи; или же добавить в таблицу tbl_dic поле d_rights, в котором хранить права доступа для незарегистрированных посетителей сайта.

Пользоваться одной таблицей прав - более разумно с точки зрения программирования, но разместить права доступа в tbl_dic вместе с другими данными по словарям - значит ускорить процесс проверки прав для незарегистрированных пользователей, сократив количество таблиц, участвующих в запросе при проверки данных.

Я свой выбор остановил на единообразии - решил хранить все права доступа в одной таблице tbl_user_dic. Если же проверка каждого обращения к данным проекта окажется ощутимой тяжестью для сервера - будем оптимизировать анонимные запросы путем кеширования или еще как-нибудь. Пока это вопрос будущего.

Итак, давайте сразу в нашу базу данных добавим запись атрибутов доступа для незарегистрированных пользователей:

insert into tbl_user_dic(ud_user, ud_dic, ud_rights) values(0,1,1);

Вот так, любой анонимный посетитель теперь имеет право на просмотр содержимого нашего первого словаря.

Теперь давайте вернемся к механизму записи и проверки атрибутов доступа. Как вы помните, права мы записываем побитно. Правда, я уже не помню, зачем добавил право 8, если есть право 4, его подавляющее (если нельзя совсем удалить описание, то можно его очистить от текста, что приравнивается к удалению), поэтому предлагаю пока заменить 8 на "reserved" - еще пригодится для чего-нибудь более полезного.

00000001 - 1 - просмотр словаря
00000010 - 2 - добавление описания
00000100 - 4 - изменение/удаление описания (чужого)
00001000 - 8 - reserved
00010000 - 16 - добавление слова
00100000 - 32 - удаление слова (чужого)
01000000 - 64 - reserved
10000000 - 128 - контроль доступа

Чтобы проверить право доступа, достаточно побитно сложить права пользователя с запрашиваемым правом на совершение действия, воспользовавшись логическим "и".

Если вы не сильны в логических операциях, привожу пример:

Права пользователя ($user): 00000011 (3) - чтение(1) и добавление описания(2)
Запрашиваемое действие ($action): 00000010 - добавление описания (2)

Складываем: $access=$user & $action;

Побитное "и" вернет нам результат: 00000010. То есть, установленными битами будут только те, которые были установлены в обеих переменных.

В этом случае пользователь получает "добро" на совершение операции.

Но у нас есть не только права для конкретного пользователя, но и права для всех пользователей, и было бы большой ошибкой - не дать пользователю совершить операцию, разрешенную для всех, но не прописанную специально для него, так как пользователь может разрегистироваться и совершить эту операцию как анонимный пользователь. Поэтому перед проверкой доступа следует сложить права для всех с правами данного пользователя. Для этого лучше всего подходит логическое сложение "или". Немного изменим наш пример:

Права для всех ($all): 00000010 (2) - добавление описания
Права пользователя ($user): 00000101 (5) - чтение(1) и изменение описания(4)
Запрашиваемое действие ($action): 00000010 - добавление описания (2)

Накладываем общие права на частные: $user=$all | $user;

Теперь права $user равны 00000111.

$access=$user & $action;

Содержимое $access получилось ненулевым 00000010, а это значит, что доступ пользователю должен быть предоставлен!

Поскольку мы не планируем запрашивать несколько атрибутов действий в одном обращении, то после логического "и" мы можем проверить результат как на равенство с запрашиваемым номером атрибута, так и просто проверить на отличность результата от нуля.

Для пущей понятности привожу пример "запретного" варианта:

$all: 00000001 (1) - чтение
$user: 00000011 - чтение и добавление описания
$action: 00100000 (32) - добавление слова
$all | $user = 00000011
$access = 00000000, так как ни одного бита в правах не совпало с битом, определяющим право на добавление слова.

Фуф, по-моему, разжевал эту тему до консистенции детского питания. Давайте теперь запишем проверку доступа в виде функции:

<?   function user_access($dic$action=1$user_id=0)   {    $dic=(int)$dic;    $action=(int)$action;    $user_id=(int)$user_id;    if(!$dic) return(11); // не выбран словарь (не должно такого случаться)    if(!$action) return(0); // не запрошено действие (никаких прав не выдано)    // запрашиваем публичные права на словарь    $err=$this->sql_run('select ud_rights from tbl_user_dic whre ud_user=0 && ud_dic='.$dic);    if($err) return($err);    if(!list($all_rights)=mysql_fetch_row($this->sql_res)) return(12);    // проверяем общий доступ    if($all_rights $action) return(0); // положительный ответ    // проверяем частный доступ, если задан user_id    if($user_id)    {     $err=$this->sql_run('select ud_rights from tbl_user_dic whre ud_user='.$this->u_id.' && ud_dic='.$dic);     if($err) return($err);     if(list($user_rights)=mysql_fetch_row($this->sql_res))     {      // складываем маски и проверяем доступ      if(($user_rights $all_rights) & $action) return(0); // положительный ответ     }    }    return(1002); // нет прав   } ?>

По-моему, тут даже объяснять нечего - все сказано в комментариях. Если что-то непонятно - обращайтесь ко мне на форум.

Не забываем записать в errors.txt новые ошибки

11	не выбран словарь - ошибка управления или попытка взлома системы;
администратору направлен отчет о произошедшем
12	для данного словаря не определены права общего доступа; 
администратору отправлено сообщение

...

1002	у вас недостаточно прав для совершения этой операции

Продолжим?





[шаг назад] [печатать] [в начало сайта]



copyright ©2000-2017 Ruslan Kurepin