Хобрук: Ваш путь к мастерству в программировании

Контроль доступа и запросы XHR

Я борюсь с реализацией контроля доступа для пользовательской среды.

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

Вот структура базы данных:

пользователи:

  • Джон
  • Мэри
  • Грег

группы_пользователей:

  • Администраторы
  • Бухгалтеры
  • Менеджеры

users_to_user_groups:

  • Джон => Администраторы
  • Мэри => Бухгалтеры
  • Грег => Менеджеры

ресурсы (действия контроллера):

  • пользователи/изменить
  • счета/добавить
  • клиенты/удалить

resources_to_user_groups:

  • пользователи/изменить => Администраторы
  • счета/добавить => Бухгалтеры
  • клиенты/удалить => Менеджеры

А вот и [псевдо]код.

$user = new User; // This will be currently logged in user ...

$acl = new Acl($user);

$dispatcher = new Dispatcher($acl);

$dispatcher->dispatch('users', 'new');

class Dispatcher
{
    public function dispatch($controller, $action)
    {
        $permission = $controller . '/' . $action;

        if(!$this->acl->isAllowed($permission))
        {
            throw new AccessDeniedException("Access denied");
        }

        // User is authorized to execute this action, dispatch ...
    }
}

Мне нравился этот подход... пока я не понял, что XHR-запросов тоже много.

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

Значит, должна быть какая-то группировка ресурсов, например, новая таблица resource_groups:

  • Список счетов (счета/список, счета/xhr_get_total_amount)
  • Список заказов (заказы/список, заказы/xhr_get_positons_for_order, заказы/xhr_get_some_other_data)
  • Добавить нового пользователя (users/new) # Одно действие, форма ввода нового пользователя не использует запросы XHR

... и вместо того, чтобы назначать ресурсы группам пользователей, назначайте группы ресурсов группам пользователей.

Чувствуется так сложно. Это правильный способ сделать это? Что можно улучшить? Решает ли какая-либо структура эту проблему?


  • Почему XHR должен иметь значение? Один и тот же пользователь с теми же правами получает доступ к одному и тому же ресурсу таким же образом, просто он упаковывается и доставляется клиенту другим способом. Если это нечто большее, то здесь недостаточно информации, чтобы оказать вам какую-либо значимую помощь. 23.05.2013
  • Джейсон - потому что один «ресурс» (лучше формулировка - «активность», как упоминал DudeOnRock) может состоять из одного статического HTTP-запроса или, кроме того, вызывать один или несколько запросов XHR. Таким образом, мы не можем считать, что каждая пара controller::action является «разрешением», нам нужно их как-то сгруппировать. 23.05.2013
  • Мне кажется, что вы где-то свернули не туда. Если вы создаете разрешения на основе запросов (или, если быть максимально буквальным, каждый URL-адрес имеет свое собственное конкретное разрешение), то вы идете по пути, который невозможно поддерживать. Создание групп для добавления этих запросов просто немного абстрагирует проблему обслуживания. Теперь вы не будете первым, кто применит этот подход (устаревшая система, используемая в моей работе, изначально основанная на osCommerce, контролирует доступ для каждого имени файла), но если ваше приложение сейчас или имеет стремление быть хоть сколько-нибудь скромным размер, вас ждут головные боли. 23.05.2013
  • Да, вы правы в моем первоначальном плане, когда для каждой пары controller::action (или URL) требуется отдельное разрешение. Но, как я уже упоминал в конце поста, я вижу необходимость группировать некоторые действия вместе, чтобы сформировать единое разрешение/действие. Каков предлагаемый вами подход? Я привожу вам пример - просмотр журналов активности, который состоит из 2 действий контроллера - один статический HTTP-запрос, который рисует HTML-разметку таблицы, а на этой странице также есть один XHR-запрос, который получает последние записи журнала, скажем, каждые 30 секунд. Как вы объединяете те, у кого есть одно разрешение? 23.05.2013
  • @LaurisB: ваш запрос XHR может вызывать несколько разных функций, которые представляют действие в принимающем скрипте. Если некоторым из этих функций не нужны разрешения, это нормально, если все они нужны, аутентифицируйте каждое действие отдельно. 23.05.2013
  • @DudeOnRock: Можете ли вы рассказать об этом на простом примере? Нужно ли мне проходить аутентификацию против чего-либо еще, кроме действий контроллера? 24.05.2013

Ответы:


1

Я имел дело с той же проблемой в прошлом году, и вот как я решил ее.

Прежде всего, я использовал библиотеку ACL Zend Framework в качестве базового движка. чтобы сообщить мне, есть ли у какого-либо пользователя доступ к какому-либо ресурсу. Поскольку ZF уже поддерживает группировку пользователей и роли (включая иерархию ролей), вам больше не нужно об этом беспокоиться.

Если оставить в стороне группировку пользователей и роли, следующей будет группировка ресурсов, которую ZF не поддерживает внутренне (к сожалению). И я считаю, что это часть вашего вопроса касается. Тем не менее, вы можете использовать ZF и расширять его в соответствии со своими потребностями. Все, что вам нужно сделать, это придумать механизм группировки ресурсов (плоский или иерархический). Затем вы можете использовать ZF, как указано в их руководстве.

Вот пример того, как это сделать:

  1. Создайте механизм ACL и другие базовые объекты:

    $acl = new Zend_Acl();
    
    $acl->addRole(new Zend_Acl_Role('guest'))
        ->addRole(new Zend_Acl_Role('member'))
        ->addRole(new Zend_Acl_Role('admin'));
    
    $parents = array('guest', 'member', 'admin');
    $acl->addRole(new Zend_Acl_Role('someUser'), $parents);
    
  2. Определите группу ресурсов:

    $resources = array(
        'group 1' => array(
            'resource 1'
            , 'resource 2'
            , 'resource 3'
        )
        , 'group 2' => array(
            'resource 1'
            , 'resource 4'
            , 'resource 5'
        )
    );
    
  3. Представьте свои ресурсы механизму ACL:

    function addResource(Zend_Acl $acl, $resources, $groupName)
    {
        foreach ($resources[$groupName] as $resource) {
            $acl->add(new Zend_Acl_Resource($resource));
        }
    }
    
    addResource($acl, $resources, 'group 2');
    
  4. Используйте механизм ACL для запроса разрешений:

    echo $acl->isAllowed('someUser', 'resource 1') ? 'allowed' : 'denied';
    

Как видите, я ничего особенного здесь не делал. Единственная новая концепция, представленная здесь, заключалась в том, что ресурсы, добавляемые в механизм ACL, отличались от тех, которые использовались для запроса. Но это было сделано за уровень до того, как мы фактически вызвали библиотеку ZF, поэтому вызовы для запроса ACL ZF все еще работают.

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

28.05.2013
  • Да, это похоже на то, что я думал о группировке ресурсов. Я выберу пользовательскую реализацию, где группы ресурсов будут «разрешениями». 28.05.2013
  • Лично я считаю, что иерархия ресурсов более полезна. В этом случае все, что вам нужно иметь в виду, это использовать пути вместо имен групп. Например, /branch 1/branch 1.1, что означает, что у вас есть массив в PHP, например $resources['tree']['branch 1']['tree']['branch 1.1']. И вам нужно объединить массивы $resources['resources'] и $resources['tree']['branch 1']['resources'] и $resources['tree']['branch 1']['tree']['branch 1.1']['resources'], чтобы составить список ресурсов, с которыми они поставляются. Я уверен, что вы сами можете понять необходимость использования записей tree и resources. 28.05.2013

  • 2

    Почему бы просто не добавить в таблицу resources новый столбец с именем descendants, в котором будет храниться массив зависимых ресурсов xhr? Таким образом, это может выглядеть так:

    resource: "invoices/list"
    descendants: ["invoices/xhr_get_total_amount"]
    
    resource: "orders/list"
    descendants: ["orders/xhr_get_positons_for_order","orders/xhr_get_some_other_data"]
    
    resource: "users/new"
    descendants: []
    

    Кроме того, если еще не реализовано: вы можете получить и обработать весь список разрешенных ресурсов и их потомков в один массив в начале запроса и хранить их до ответа. Таким образом, вы не будете спрашивать базу данных каждый раз, когда вам нужно что-то проверить или получить доступ.

    25.05.2013

    3

    Я знаю, что не отвечаю прямо на ваш вопрос, но, возможно, я могу направить вас по несколько иному пути, который станет намного более гибким, когда ваш веб-сайт станет больше и сложнее. После того, как я прочитал этот пост Я переключил свою систему аутентификации на основе действий (разрешить действие "doSomething"), а не на основе ролей ("администратор" может делать следующее....).

    Просто мысль.

    23.05.2013
  • Как вы справляетесь с управлением разрешениями, когда какая-то «активность» использует XHR? Например, действие Добавить нового пользователя, которое в дополнение к рендерингу HTML-формы (users/new) использует XHR для получения некоторых данных (например, изменение комбинации стран в HTML-форме получает города для этой страны, такие как users/xhr_get_cities_by_country_id). 23.05.2013
  • действие addNewUser не должно нести ответственность за какие-либо выходные данные. Он должен просто добавить нового пользователя в базу данных. 23.05.2013
  • Плохо, с Добавить нового пользователя я подумал о новой пользовательской форме. Как и в именовании REST: пользователи/новые (форма) => пользователи/создать (добавить в БД) и пользователи/редактировать/5 (форма) => пользователи/обновить/5 (обновить в БД). 24.05.2013

  • 4

    Предпочтительно использовать не *, а домен, который запрашивает файл. * не работает в какой-то версии IE (не помню какой).

    if ($ref_url)
      header("Access-Control-Allow-Origin:"+$ref_url);
    else
      header("Access-Control-Allow-Origin:*");
    
    25.05.2013
    Новые материалы

    Основы принципов S.O.L.I.D, Javascript, Git и NoSQL
    каковы принципы S.O.L.I.D? Принципы SOLID призваны помочь разработчикам создавать надежные, удобные в сопровождении приложения. мы видим пять ключевых принципов. Принципы SOLID были разработаны..

    Как настроить Selenium в проекте Angular
    Угловой | Селен Как настроить Selenium в проекте Angular Держите свое приложение Angular и тесты Selenium в одной рабочей области и запускайте их с помощью Mocha. В этой статье мы..

    Аргументы прогрессивного улучшения почти всегда упускают суть
    В наши дни в кругах веб-разработчиков много болтают о Progressive Enhancement — PE, но на самом деле почти все аргументы с обеих сторон упускают самую фундаментальную причину, по которой PE..

    Введение в Джанго Фреймворк
    Схема «работать умно, а не усердно» В этой и последующих статьях я познакомлю вас с тем, что такое фреймворк Django и как создать свое первое приложение с помощью простых и понятных шагов, а..

    Настольный ПК как «одно кольцо, чтобы править всеми» домашних компьютеров
    Вид после 9 месяцев использования С настольных компьютеров все началось, но в какой-то момент они стали «серверами», и мы все перешли на ноутбуки. В прошлом году я столкнулся с идеей настольных..

    Расширенные методы безопасности для VueJS: реализация аутентификации без пароля
    Руководство, которое поможет вам создавать безопасные приложения в долгосрочной перспективе Безопасность приложений часто упускается из виду в процессе разработки, потому что основная..

    стройный-i18следующий
    Представляем стройную оболочку для i18next. Эта библиотека, основанная на i18next, заключает экземпляр i18next в хранилище svelte и отслеживает события i18next, такие как languageChanged,..