Реализация ACL на основе переменных, а не статических ролей

Я хотел бы использовать Zend ACL (Zend\Permissions\Acl) не (только) на основе статических ролей, но также и на (переменных) пользовательских точках.

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

Пример

Ресурсы:

  • Ресурс 1:20 баллов
  • Ресурс 2: 100 баллов
  • Ресурс 3: 150 баллов

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

  • Пользователь 1:70 баллов => Доступ к ресурсу 1
  • Пользователь 2: 135 баллов => Доступ к ресурсам 1, 2
  • Пользователь 3: 170 баллов => Доступ к ресурсам 1, 2, 3

Как лучше всего это сделать?

Мои мысли на данный момент

  1. Создать объект ACL динамически для текущего пользователя, вошедшего в систему, на основе его баллов (установить каждый $acl->allow() на основе баллов). Это не чисто.
  2. Создайте общий ACL и каким-то образом передавайте баллы пользователя (мне удалось сделать это с помощью утверждений. См. Мой ответ ниже).
  3. Здесь предлагается какой-то (возможно, более простой / более чистый) способ ...

Буду очень признателен за толчок в правильном направлении :)


person lorey    schedule 28.05.2013    source источник
comment
Обычно ACL динамически создают из defs, хранящихся в базе данных. Было бы просто учесть моменты, чтобы сделать это тоже. Вы можете использовать утверждения для проверки пороговых значений баллов без проблем   -  person Andrew    schedule 28.05.2013
comment
Может ли кто-нибудь взглянуть на мою попытку решить эту проблему?   -  person lorey    schedule 02.06.2013


Ответы (2)


Так что речь идет не только о Zend, но и о работе с ACL в целом.

Обычно, когда вы реализуете права доступа в ACL, вы назначаете его группе, а не отдельному пользователю. Затем вы можете легко (и динамически) добавлять или удалять пользователей из групп.

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

person Adrian World    schedule 28.05.2013
comment
Вот что меня беспокоит. Количество разных баллов / баллов действительно велико, и поэтому мне нужно было бы выполнить много работы по настройке, которая не кажется правильной для такой простой задачи (сравните текущие баллы с необходимыми баллами). Вот почему я прошу более элегантного решения. Чтобы прояснить: я прочитал (и, надеюсь, понял) полную документацию по этому вопросу, но все еще не уверен, как это сделать. - person lorey; 28.05.2013
comment
@lorey Распространенное заблуждение, что простую задачу быстро выполнить. На самом деле это легко реализовать, но там, где это обычно бывает сложно, как с вашим проектом, и с таким количеством разных баллов / баллов. - person Adrian World; 28.05.2013
comment
Должен быть способ попроще. Если я вас правильно понял, вы предлагаете иметь группы вроде 0to25points, 26to29points, 30to69points до 5000? Имхо, по крайней мере, было бы проще создать один конкретный объект ACL для текущего пользователя. Поправьте меня, если я ошибся ... - person lorey; 28.05.2013
comment
Объекты @lorey ACL обычно привязаны к ресурсам, а не к пользователям. Если вы связали его с пользователем, вам нужно было бы добавить ACL к ресурсу для каждого (нового) пользователя. Немного сложно увидеть полную картину вашего проекта и придумать лучшее решение. - person Adrian World; 28.05.2013
comment
Я знаю, что изменил бы концепцию ACL, если бы сделал это так. Вот почему я надеюсь, что есть лучшее решение. Я понимаю, что это сложно. Надеюсь, что кто-то сделал что-то подобное и уже имеет чистое решение :) - person lorey; 29.05.2013
comment
Сегодня я добавлю простой пример, вы его слишком усложняете;) - person Andrew; 29.05.2013
comment
Спасибо, ценю ваши старания :) - person lorey; 29.05.2013
comment
Я также опубликовал решение, которое придумал на данный момент. Было бы неплохо, если бы вы тоже на него взглянули! - person lorey; 29.05.2013

Ладно, сам пробовал реализовать. Может быть, это не красиво, но это лучшее решение, которое я придумал сам. Это правильное направление? Буду признателен за любые отзывы!

Решение:

Вместо строк в качестве ресурсов и ролей я использую свои модели (предложено здесь). Я использую PointResourceInterface, чтобы отмечать ресурсы, требующие определенного количества баллов, и реализую Zend\Permissions\Acl\Role\RoleInterface в моем пользовательском классе. Теперь создаю новый NeededPointsAssertion:

class NeededPointsAssertion implements AssertionInterface
{
    public function assert(Acl $acl, RoleInterface $role = null, 
            ResourceInterface $resource = null, $privilege = null) {
        // Resource must have points, otherwise not applicable
        if (!($resource instanceof PointResourceInterface)) {
            throw new Exception('Resource is not an PointResourceInterface. NeededPointsAssertion is not applicable.');
        }

        //check if points are high enough, in my app only users have points
        $hasEnoughPoints = false;
        if ($role instanceof User) {
            // role is User and resource is PointResourceInterface
            $hasEnoughPoints = ($role->getPoints() >= $resource->getPoints());
        }

        return $hasEnoughPoints;
    }
}

PointResourceInterface выглядит так:

use Zend\Permissions\Acl\Resource\ResourceInterface;

interface PointResourceInterface extends ResourceInterface {
    public function getPoints();
}

Настройка:

$acl->allow('user', $pointResource, null, new NeededPointsAssertion());

Пользователи имеют доступ к ресурсам, которым нужны баллы. Но дополнительно проверяется NeededPointsAssertion.

Доступ. Я проверяю, разрешен ли доступ следующим образом:

$acl->isAllowed($role, $someResource);

Если есть пользователь $role = $user, иначе это guest или что-то еще.

Источник вдохновения http://www.aviblock.com/blog/2009/03/19/acl-in-zend-framework/

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

person lorey    schedule 29.05.2013