Реализация ограничений ACL, более чем разрешить/запретить
я разработал небольшую, но эффективную структуру MVC-стиля для использования в приложении, и я реализую проверку ACL на запрос.
быстрые детали: PHP 5.3+; MySQL 5.1+; Custom framework,"MVC-like"
на данный момент проверка ACL проста "запретить, если не белый список"; каждый group
можно назначить разрешение определенным обработчикам запросов. Например:
privilege permission
+----------+---------------+ +---------------+---------------+
| group_id | permission_id | | permission_id | handler_key |
+----------+---------------+ +---------------+---------------+
| 1 | 1 | | 1 | lorem_ipsum |
| 1 | 2 | | 2 | hello_world |
| 2 | 3 | | 3 | foobar |
+----------+---------------+ +---------------+---------------+
(user
и group
исключены для краткости, но в их моделях нет ничего необычного)
в любом случае, мой фреймворк направляет URIs в соответствующий handler_key
через таблицу обработчика / пути (для разделения архитектуры файловой системы) запрос затем отправляется обработчику, учитывая group_id
связанный с запросом белый список для этого handler_key
.
мне любопытно, каков наилучший подход к реализации хранения / проверки произвольных (пользовательские) ограничения? примеры случаев:
- разрешить данной группе вызывать обработчик только в будние дни, с 8: 00 до 17:00.
- разрешить только данной группе вызывать обработчик для изменения "принадлежащих" данных; т. е.: данные, созданные связанным
user
. эта проверка будет включать, возможно, проверкаuser_id
поле, связанное с содержимым, которое будет изменено обработчиком, иuser_id
связанные с запрос
я flags
столбец, однако это не является будущим доказательством с введением дополнительных требований к функциям, группам и ограничениям. Я думал в следующем направлении, но что использовать?
permission
+---------------+----------------------------+
| permission_id | handler_key | constraint |
+---------------+---------------+------------+
| 1 | lorem_ipsum | ? |
| 2 | hello_world | ? |
| 3 | foobar | ? |
+---------------+---------------+------------+
ненужное уточнение:
( Примечание: код был набран здесь, а не copypasta из project)
чтобы прояснить некоторые из жаргона здесь;обработчики (в частности, веб-обработчики) по существу контроллеры для тех, кто знаком с архетипом в MVC.
их конкретная реализация представляет собой один PHP-файл, который возвращает функцию, вызываемую диспетчером или вызывающим суб-обработчиком. Например:
<?php
$meta = array('subhandlers' => array());
return function($request, $response) use($meta){
$response['foo'] = 'bar';
};
мой фреймворк использует веб-обработчики и API-интерфейс обработчиков; веб-обработчики передают данные в объект ответа (в основном набор иерархических вид), который генерирует HTML. Данные получены путем вызова обработчиков API, которые просто возвращают необработанные данные (обработчики API можно рассматривать как представления модель, возвращаясь к типичному MVC)
составные обработчики по существу являются слоем абстракции, поскольку они сами являются обработчиками, которые вызывают обработчики для агрегирования данных. Моя текущая реализация проверки ACL делает беглую проверку всех вложенных обработчиков (через $meta
массив переменная, объявленная в качестве заголовка метаданных для обработчика) например:
<?php
$meta = array('subhandlers' => array('my_subhandler'));
return function($request, $response) use($meta){
$someData = Caller::call('my_subhandler', array($request, $response));
$response->bind($someData);
};
2 ответов
видео, которое я опубликовал в своем комментарии, имеет некоторые похожие идеи на те, которыми вы поделились, но без кода.
Что касается вашего вопроса, я никогда не реализовывал это, и у меня есть только смутное представление о том, как такая система может (или не может) быть построена, поэтому возьмите мой ввод С (или несколькими) зернами соли.
первое, что вы должны сделать, это определить ограничения, которые пользователь может ограничить, забыть о произвольных данных, определяя, что пользователь может и не может определить самый важный момент здесь.
следующий шаг-определить какую-то нотацию или структуру данных, которую вы можете легко проанализировать и проверить, например, во временных ограничениях у вас есть следующие возможности:
- конкретные даты и время (2011-05-26)
- диапазоны datetime (2011-05-26-2011-05-31)
- рекурсивные даты (201x-05-26 или каждую пятницу)
- логические (и / или / xor) операторы
Если у вас есть нотация propper, которую вы можете легко разобрать и проверить с помощью маркирования правило и, возможно, с помощью чего-то DatePeriod или DateInterval или даже оператор модуля, как crontab.
второй пример:
Разрешить вызов только данной группе обработчик для изменения "принадлежащих" данных; ie: данные, созданные связанным пользователем.
звучит как простой ACL для я:
- ресурс: конкретные данные
- роль: конкретный пользователь
тогда, конечно, у вас есть более сложные правила, такие как:
пользователь, утверждающий запись, должен имеют равный или более высокий уровень (в же пространство имен) как пользователь кто создал запись, но они не могут будьте тем же пользователем.
Я думаю, что такие правила должны быть специфичными для логики приложения и истинными универсальное решение было бы чрезвычайно сложно реализовать, Зед шоу упомянул в своем выступлении, что он придумал полное решение, которое использует только 400 строк кода, мне было бы очень интересно узнать, как он это сделал.
флаги (хранящиеся в битах) - отличный (хотя и загадочный) способ указания комбинации одного или нескольких ограничений, но по моему опыту лучше, если вы определяете все ограничения apriori.
Так как вы, кажется, не знаете точно ограничения, которые вы хотите проверить, я предлагаю вам создать обозначения для нескольких типов ограничений, которые вы хотите проверить:
- времени на основе
- пользователей/ресурсов
- ...
а затем реализовать методы, которые анализируют (возможно, с нотацией, которая подразумевает версию, поэтому вы можете перенести в будущем) и проверить все ограничения.
Мне жаль, если мой ответ не очень поможет вам, но я нахожу вопрос очень интересным и Я надеюсь, что кто-то другой придумает лучше, AFAIK нет волшебной палочки, чтобы сделать это.
рассмотрев мой архитектурный выбор, мне стало ясно, что я могу воспользоваться своим handler
стиль обработки запросов подход.
(пожалуйста, критикуйте и/или высмеивайте и / или дайте пять это предложение как оправдание)
запрос на проверку наличия у пользователя разрешений может, для этих целей,рассматриваться как просто другой запрос, поэтому требуется собственный обработчик. Для пример:
permission
+---------------+--------------------------------------+- - - - - -+
| permission_id | handler_key | constraint_handler_key | arguments :
+---------------+-------------+------------------------+ - - - - - +
| 1 | lorem_ipsum | user_check_owner | :
| 2 | hello_world | user_check_owner | :
| 3 | foobar | time_check | :
+---------------+-------------+------------------------+ - - - - - +
С NULL
-able constraint_handler_key
столбец, новые ограничения могут быть созданы программно и административно делегированы.
когда запрос срабатывает, платформа агрегирует цепочку обработчиков и сравнивает ее с белым списком, как это уже делается. В случае a (возможно, с аргументами, как следует из приведенной выше таблицы) он выполняет поиск в handlerTable
связанный с этим запросом тип:
// web handlers handlerTable example
return array(
'lorem_ipsum' => PATH_WEB_HANDLERS . 'path/to/lorem_ipsum.handler.php',
);
// acl handlers handlerTable, follows same format
return array(
'time_check' => PATH_ACL_HANDLERS . 'time/check.handler.php',
);
(обработчики API также идентичны)
обработчик ACL должен возвращать только логические значения, таким образом продолжая или заканчивая последовательность проверки разрешений, и, следовательно, весь запрос.
// time_check acl handler, allow if current time between 9am - 5pm
return function($request){
$dayBegin = time() - (time() % 86400);
return (time() > ($dayBegin + 32400) && ($dayBegin + 61200) > time());
};
случаи упущения constraint_handler_key
s обрабатываются как основные проверки белого списка;разрешить-если / запретить-если-нет.
поэтому мой каталог приложений начнет выглядеть так:
:
+- application/
| +- config/
| +- views/
| +- handlers/
| +- acl/
| +- api/
| +- web/
: