Введение

В настоящее время я создаю систему контроля доступа в своей установке DataMapper ORM (с CodeIgniter 2. *). У меня начальная инъекция прав пользователя (также корневые / анонимные слои) работает отлично. Когда Пользователь входит в систему, вызовы DataMapper, которые выполняются в системе, автоматически помечаются правами пользователя, которыми обладает Пользователь.

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

У меня есть два специальных вызова, поэтому я тоже могу отключить проверку прав пользователей. Это особенно удобно в тот самый момент, когда я хочу войти в систему и мне нужно выполнить начальные проверки;

DataMapper::disable_userrights();

$this->_user = new User($this->session->userdata('_user_id'));
$this->_userrights = ($this->_user ? $this->_user->userrights(TRUE) : NULL);

DataMapper::enable_userrights();

Вышеупомянутое гарантирует, что я могу выполнить первоначальную инъекцию пользователя (и его прав пользователя). Внутри библиотеки DataMapper я использую $CI =& get_instance(); для доступа к глобальным объектам _, которые я использую. Общее правило в этой статье, которую я создаю, заключается в том, что $this->_ зарезервирован для "глобальной" системы, которая всегда загружается (или иногда может иметь значение NULL / FALSE), поэтому я могу легко получить доступ к информации, которая почти всегда требуется для каждого страница / звонок.

Подробности

Хорошо, на изображении выше, мой вошедший в систему Пользователь имеет права пользователя: Create/Read/Update на User Entity. Итак, теперь, если я назову простой:

$test = new User();
$test->get_where('name', 'Allendar');

Массив $_rights внутри экземпляра DataMapper будет знать, что текущий вошедший в систему Пользователь может выполнять определенные задачи на «этом» экземпляре;

protected $_rights = array(
    'Create' => TRUE,
    'Read' => TRUE,
    'Update' => TRUE,
    'Delete' => FALSE,
);

Проблема

Теперь пришла моя проблема. Я хочу контролировать эти права пользователей, проверяя их для каждого выполняемого действия. У меня есть следующие идеи;

  1. Супер избыточность; создайте глобальный метод проверки, который выполняется в начале каждого другого метода в классе DataMapper.
    • Проблема 1. Мне нужно спамить весь класс DataMapper одними и теми же вызовами.
    • Проблема 2. У меня нет контроля над методами расширения DataMapper.
    • Проблема 3. Как определить реляционные включения? Их тоже нужно проверить.
  2. Привязка низкого уровня для определенных вызовов Core DataMapper, где я могу четко определить, какое действие выполняется в базе данных (C/R/U/D).

Так что я стремлюсь к Варианту 2 (и 1.) Problem 2), так как он также решит 1.) Problem 2.

Проблема в том, что DataMapper настолько массивен, что довольно сложно понять, что на самом деле происходит, когда он находится на самом глубоком уровне вызовов. Более того, похоже, что все методы очень разбросаны и почти никогда не используют друг друга ($this->get() часто не используется для выполнения конечного вызова для получения набора данных).

Итак, моя цель:

  • Пользователь (авторизованный, анонимный, root) делает DataMapper istance
    • $user_test = new User;
  • Пользователь хочет получить $user-test (Read)
    • $user_test->get(1);
  • DataMapper проверит фактический вызов, который выполняется в базе данных.
    • ЕСЛИ это только ВЫБРАТЬ; ОК
    • ЕСЛИ что-то еще, кроме SELECT (или ПРИСОЕДИНЯЕТСЯ к другой модели, к которой у пользователя нет доступа к этой / этим моделям, произойдет сбой с четким сообщением об ошибке)
    • IF JOINed Models также проверяет; ОК
  • Верните фактический экземпляр;
    • ЕСЛИ ОК: продолжить обычный рабочий процесс DataMapper.
    • ЕСЛИ НЕ ВЕРНО: проинформируйте пользователя и верните обычный пустой экземпляр DataMapper этой модели.

Кроме того, для этой системы, я думаю, мне нужно будет добавить некоторую настройку для вызовов SQL raw_sql (и т. Д.), Чтобы мне пришлось вручную вводить права, связанные с этим оператором SQL, или разрешать только Root Пользователь, чтобы делать эти вещи.

Резюме

Мне любопытно, пробовал ли кто-нибудь когда-нибудь что-то подобное в DataMapper или есть какие-то подсказки, как я могу использовать / перехватывать эти вызовы самого низкого уровня в DataMapper.

Если я смогу получить некоторое разрешение на самом глубоком уровне фактического финального запроса-запроса DataMapper, я, вероятно, смогу и сам пройти долгий путь.

1
user1467267 18 Янв 2014 в 14:26

1 ответ

Лучший ответ

Я бы посоветовал не делать этого в самом Datamapper (в основном из-за сложности кода, как вы уже сами заметили).

Вместо этого используйте базовую модель и расширьте Datamapper. Затем добавьте код в базовую модель, необходимую для ваших проверок ACL, а затем перегрузите каждый метод Datamapper, который требует проверки ACL. Попросите его вызвать ваш ACL, обработать отказ в доступе и, если доступ предоставлен, просто вернуть результат parent::method();.

Вместо того, чтобы расширять Datamapper, ваши модели приложений должны затем расширять эту базовую модель, чтобы они унаследовали функции ACL.

2
WanWizard 18 Янв 2014 в 20:17
Спасибо, Харро. Исправлено, сохранив всю логику в отдельном классе DM_model, расширяющем DataMapper. Я храню его в файле библиотеки datamapper. Есть ли более чистый способ подключить его к DataMapper? Проблема в том, что когда я сохраняю его только в папках Models, это создает проблемы, тогда как DataMapper хочет вызвать связанную таблицу (имя).
 – 
user1467267
19 Янв 2014 в 15:30