Минималистичная система разделения прав по группам за 5 минут

Автор оригинала: Rasmus
  • Перевод
Замучались с ACL? Есть пожалуй самое простое решение для разделения прав по группам. Никаких ACL таблиц, никакого дерева прав. Но если вам требуется задавать права персонально для каждого пользователя, то это решение точно не для вас.

У нас есть всего 5 минут, поэтому давайте сразу начнем.

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

users
    id - primary
    username - unique
    password
    group_id
groups
    id - primary
    name - unique


Потом создаем несколько групп и пользователей. Не забудьте создать группу «Администраторы»

Далее создаем классы моделей пользователей и групп

<?php
class User extends AppModel {
    var $name = 'User';
    var $displayField = 'username';
    var $belongsTo = array(
        'Group' => array(
            'className' => 'Group',
            'foreignKey' => 'group_id'
        )
    );
}
?>


<?php
class Group extends AppModel {
    var $name = 'Group';
    var $displayField = 'name';

    var $hasMany = array(
        'User' => array(
            'className' => 'User',
            'foreignKey' => 'group_id',
            'dependent' => false
        )
    );

}
?>


И добавляем в app_controller.php следующий код:

<?php
class AppController extends Controller {

    var $components = array('Auth');
    var $permissions = array();
   
    function beforeFilter() {
        $this->Auth->fields  = array(
            'username'=>'username', // Поле в базе с логином пользователя
            'password' =>'password' // Поле с паролем
        );
        $this->Auth->authorize = 'controller';
        $this->Auth->autoRedirect = false;
        $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
        $this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
        $this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'welcome');

    }
   
    function isAuthorized(){
        if($this->Auth->user('group') == 'Администраторы') return true; // Если не хотите давать доступ для группы "Администраторы" ко всему по умолчанию, закомментируйте эту строчку
        if(!empty($this->permissions[$this->action])){
            if($this->permissions[$this->action] == '*') return true;
            if(in_array($this->Auth->user('group'), $this->permissions[$this->action])) return true;
        }
        return false;
       
    }

}
?>


Добавляем в users_controller.php такие строки:

<?php
class UsersController extends AppController {

    var $name = 'Users';
    var $helpers = array('Html', 'Form');
    var $permissions = array(
        'logout' => '*',
        'welcome' => '*'
    );
   
    function welcome(){
    }

    function login(){
        if($this->Auth->user()){
            $this->Session->write('Auth.User.group', $this->User->Group->field('name',array('id' => $this->Auth->user('group_id'))));
            $this->redirect($this->Auth->redirect());
        }
    }
   
    function logout(){
        $this->redirect($this->Auth->logout());
    }

    // Ну и прочие необходимые вам методы, например add, edit, delete
?>


Ну вообщем-то все. Теперь что бы указать права доступа необходимо добавить $permissions для любого контроллера как мы сделали это в users_controller

Как это работает:

Когда пользователь заходит мы добавляем название его группы в Auth сессию. После когда мы обращаемся к методу контроллера, компонент Auth вызывает нашу функцию isAuthorized и если она возвращает true, то пользователь получает доступ, а если она возвращает false, то запрещает его. Если пользователь находится в группе «Администраторы», то он всегда получает доступ. Функция isAuthorized проверяет массив $permissions указанные в каждом контроллере используя в качестве ключа название текущего action и если группа пользователя есть в массиве по этому ключу (ну или вместо массива там стоит '*' — то есть всем) то пользователю разрешается доступ.
Примечание: Подразумевается, что вы все равно авторизовались, даже если уровень доступа '*'. Можно разрешить заходить неавторизованным пользователям воспользовавшись методом Auth->allow
Примечание: Мы не определяли доступ к users/login, потому что Auth по умолчанию разрешает к нему доступ.

Пример:

Допустим мы хотим разрешить группе «Модераторы» удалять пользователей. Добавим следующий код в users_controller.php:

var $permissions = array(
        'logout' => '*',
        'welcome' => '*'
        'delete' => array('Модераторы')
    );


Но ведь пользователи который не авторизовались не смогут зарегистрироваться. Добавим в users_controller.php:

function beforeFilter(){
    $this->Auth->allow('signup');
    parent::beforeFilter();
}


Надеюсь это решение вам помогло. Это исключительно простое решение для разделения прав по группам, ну конечно у него есть свои недостатки. Например нельзя разрешить пользователю изменять статью только в том случае если он ее создал. Ну по крайней мере без изменений приведенного кода. Но я оставлю это для вас.
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 19

    +3
    Что сложного может быть с ACL?

    И, кстати, представьте, что проект начал развиваться и понадобилось сделать привязку юзера к нескольким группам, а то и сделать права только для одного юзера. Сколько вы кода будете переписывать? Зачем делать *такие* велосипеды?
      +1
      Да, согласен. Указывать имена пользователей не так уж сложно, хотя если у Вас там армия модераторов, но для таких проектов эдакое пятиминутное решение не подойдёт — надо более изысканно.
      А так, может пригодится…
        +2
        Зачем использовать с самого начала значительно более слабое решение? Оно быстрее в реализации? Есть какие-то ограничения со стороны хостинга? Еще какие-то причины?
          –2
          Его быстрее реализовать, оно быстрее работает (как минимум на количество запросов к ACL).
          И да, иногда достаточно разделения по группам и действиям.

          Опять таки, в определенных пределах решение расширяемо.
            +1
            Насколько быстрее? На один час? Какой ценой встанет такая «экономия»? Стоит ли экономить миллисекунды тут?

            Иногда? Вы уверены, что сможете на 100% спрогнозировать, что в вашем проекте этого будет достаточно?

            Вы знаете, я уверен что разработчики Битрикса думали также. Теперь в популярной коммерческой CMS нельзя ограничить доступ к отдельным разделам каталога. Это нормально?!

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

            > Не так много как может показаться, буквально одну функцию isAuthorized, ну и почистить лишнюю переменную permissions которая перестанет быть нужной.
            Да? А проверки прав добавлять не нужно будет? А новые модели данных?
              0
              > Иногда? Вы уверены, что сможете на 100% спрогнозировать, что в вашем проекте этого будет достаточно?
              Я уверен, что я легко смогу это изменить если мне потребуется.

              > Вы знаете, я уверен что разработчики Битрикса думали также. Теперь в популярной коммерческой CMS нельзя ограничить доступ к отдельным разделам каталога. Это нормально?!
              А вы в своих проектах предусматриваете всё? А кофе он варит?

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

              > Да? А проверки прав добавлять не нужно будет? А новые модели данных?
              Нет. Тоже самое с возможностью выдачи прав по пользователям делается еще легче и тем же компонентом.

        –2
        Не так много как может показаться, буквально одну функцию isAuthorized, ну и почистить лишнюю переменную permissions которая перестанет быть нужной.
        –1
        на самом деле было бы получше, если бы вы показали не «как это работает», а формальное описание предложенной вами схемы. Мне кажется, что так было бы понятнее
          0
          Я не совсем понял, что такое формальное описание предложенной схемы.
          И что не понятно сейчас?
            0
            формальное описание — это «есть множество пользователей… есть множество прав… есть еще что-то там… пользователю разрешается доступ, если...», схемку бы какую-то.
            Ну так нагляднее вообще-то, чем читать код, или то что вы написали в «как это работает», что по сути опять же есть описание кода.
              0
              В одной группе пользователей может быть много пользователей, но это очевидно из условий задачи.

              Права мы в коде контроллера привязываем к названию группы пользователя (за что меня тут уже попинали).

              Простите :( не понимаю как упростить дальше.
        • НЛО прилетело и опубликовало эту надпись здесь
            +1
            Велосипед, причем одноколесный, потому как нет такого, например, функционала:
            — юзер может быть членом нескольких групп (ролей), разрешения определяются по сумме разрешений всех групп
            — юзер — абстракция группы из одного члена, т.е. разрешения и запреты можно выдавать конкретному юзеру.
            — юзеру или группе можно напрямую запретить, прямой запрет перекрывает соответствующие разрешения, если они есть

              0
              Безусловно в нем нет такого функционала, но если он потребуется поставьте настройку Auth в например actions и у вас все это появится, достаточно будет только сделать красивый интерфейс что бы реализовать раздачу прав по описанному функционалу.

              Эта задача для тех случаев когда это всё не требуется, ну или не требуется на первоначальном этапе.
              0
              Да что вы на человека накинулись!?
              Он лишь написал статью с примером реализации прав! СПАСИБО ему за это!
              Вам не нравится?! НЕ ПОЛЬЗУЙТЕСЬ!
              В чём проблема? Кому то для дом.страницы может приготится!
                0
                сколько можно писать ООП код на синтаксисе php4?
                да еще и другим советовать решения на нём
                  0
                  где?
                    0
                    class UsersController extends AppController {
                     var $name = 'Users';
                     function beforeFilter() {
                      //...
                     }
                    }
                    
                      0
                      Чем докажите, что это не php5?

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое