Управление правами пользователей с иерархией - PullRequest
5 голосов
/ 20 сентября 2011

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

Example hierarchy

  • В муниципалитете будет одна или несколько организаций.
  • В округе будет один или несколько муниципалитетов
  • В штате будет один или несколько округов
  • Будет одно или несколько состояний
  • Организации, муниципалитеты, округа и штаты могут быть добавлены в любое время
  • Когда организация, муниципалитет, округ добавляется в систему, пользователь, у которого уже есть разрешение на просмотр этого штата, должен автоматически иметь возможность просматривать отчеты для новой организации / муниципалитета / округа без необходимости явного разрешения администратора. , То же самое должно применяться к пользователям, которые имеют разрешение на просмотр отчетов на муниципальном уровне и уровне округа, когда в систему добавляется новый объект, находящийся ниже их иерархии.

Некоторые примеры:

Пользователь 1: Может просматривать отчеты только для организации # 1

Пользователь 2: Может просматривать отчеты для всех организаций в муниципалитете № 2

Пользователь 3: Может просматривать отчеты для всех организаций в муниципалитетах № 1 и № 2

Пользователь 4: Может просматривать отчеты по всем организациям округа # 3

Пользователь 5: Может просматривать отчеты по всем округам в штате # 3

Мой вопрос: как мне это организовать? Я не уверен в наилучшем способе назначения разрешений отчетам без назначения разрешений отдельным организациям. Это явно не практично.

Я видел несколько вопросов, касающихся ACL, но, похоже, они к этому не относятся. Если да, то объяснение того, как оно будет относиться к ACL, также будет удовлетворительным ответом.

Ответы [ 2 ]

5 голосов
/ 15 октября 2012

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

table: account_groups (Broader account groupings)
Fields:
-id_key - primary key, auto number
-group - unique index
-parent - index, foreign key=account_groups.group (this allows you to create group trees, so you can specify that a county group belongs to a state, and a municipality belongs to a county group, etc.)
-group_hierarchy - integer (0 is highest permission group, each subsequent one step lower)

table: account_levels (Account levels within a group)
Fields:
-id_key - primary key, auto number
-account_level - unique index
-group - index, foreign key=account_groups.group
-account_heirarchy - integer (same as other table but denotes heirarchy within the group

table: user_accounts (Individual user accounts)
Fields:
-id_key - primary key, auto number
-account_id - unique index, user account name
-account_level - index, foreign key=account_levels.account_level

table: user_groups (denotes which tree(s) the user has access to)
Fields:
-id_key - primary key, auto number
-account_id - index, foreign key=user_accounts.account_id
-group - index, foreign key=account_groups.group

А затем для разрешений:

table: permissions (directory of permissions that could be applied)
Fields:
-id_key - primary key, auto number
-permission - unique index, permission identifier
-other stuff you need associated with the individual permissions, based on how you want them to hook into your program

table: permissions_group_permissions (permissions applied at group level)
Fields:
-id_key - primary key, auto number
-group - index, foreign key=account_groups.group
-permission - index, foreign key= permissions.permission

table: permissions_account_permissions (permissions applied at account level)
Fields:
-id_key - primary key, auto number
-account_type - index, foreign key=account_levels.account_level
-permission - index, foreign key=permissions.permission

table: permissions_individual_permissions (permissions applied to individual accounts, if neccessary)
Fields:
-id_key - primary key, auto number
-account_id - index, foreign key=user_accounts.account_id
-permission - index, foreign key=permissions.permission
-allow_or_deny - boolean (TRUE means permission is granted, FALSE means permission if revoked. This allows you to fine tune individual accounts, either granting custom elevated permissions, or revoking individual permissions for troublesome accounts without demoting them from the group. This can be useful in some special circumstances)
-expiration - timestamp (allows you to set expiration dates for permissions, like if you want to temporarily suspend a specific action. Programmatically set default value of 00/00/00 00:00:00 as indefinite. You can do this at the account and group levels too by adding this field to those tables.)

Затем вы можете использовать php для перебораразрешения для отдельной учетной записи, сначала получая группу, связанную с уровнем учетной записи, создавая массив каждой последующей группы в иерархическом порядке, а затем перебирая иерархический порядок для текущей группы (добавляя как многомерный массив в групповой массив) изтекущий уровень учетной записи в группе до последнего существующего уровня учетной записи в группе.Затем вы должны получить все уровни учетной записи для каждой последующей группы и, наконец, получить все связанные разрешения для каждого уровня учетной записи, который был добавлен в массив.Если вы реализуете разрешения для отдельных пользователей, вам потребуется добавить массив разрешений с индивидуально примененными разрешениями и, наконец, удалить все разрешения, которые из вашего массива имеют для поля allow_or_deny значение FALSE.Если пользователю необходимо иметь доступ к нескольким деревьям, вы добавляете в таблицу account_groups запись, соответствующую идентификатору его учетной записи, обозначающую, каков наивысший уровень дерева, к которому у него есть доступ, а затем выполняете итерацию по всем последующим группам в дереве.Чтобы предоставить все соответствующие разрешения учетной записи, соберите все ассоциации групп для account_id из user_groups, а затем запустите ранее описанный процесс для каждого дерева.Если у них есть доступ только к одному дереву, вам даже не нужно использовать таблицу user_groups.

an example of how the structure fits your model:
group: USA, hierarchy = 0
group: California, parent-> USA, hierarchy = 1
group: Los Angeles, parent->California, hierarchy = 2
group: Texas, parent->USA, hierarchy = 1
group: Dallas, parent->Texas, hierarchy = 2

Члены группы USA могут получить доступ ко всему.Члены Калифорнии могут получить доступ ко всем последующим группам в иерархии для Калифорнии, но не к группам для Техаса, даже если они имеют одинаковое иерархическое значение (потому что это разные родительские ветви)

account levels:
admin, hierarchy=0
manager, hierarchy=1
analyst, hierarchy=2
staff member, hierarchy=3

Каждый уровень учетной записи имеет всеразрешений для каждого последующего уровня учетной записи.

user accounts:
Bob, manager (likes to spam junk email to everyone)

Вы по-прежнему можете отозвать разрешение электронной почты для Боба, добавив разрешение электронной почты в permissions_individual_permissions и установив для параметра allow_or_deny значение FALSE.Это позволяет вам помешать Бобу рассылать спам, не лишая его управления.

example PHP array:
$account=array(
    groups=>array(), //Step 1: array_push each group the account is a member of here. Repeat for each tree from user_groups.
    account_levels=>array(), //Step 2: loop through $account[groups], array_push each level here
    permissions=>array(), //Step 3: loop through $account[account_levels], array_push each permission here. Then do the same for individual permissions applied to the account
    restrictions=>array() //Step 4: loop through individual permissions where allow_or_deny=FALSE, array_push here (do the same for group and account level if you implemented restrictions for those tables as well). Tell your program to ignore permissions from this array, even if the account would otherwise have them.
);
1 голос
/ 22 сентября 2011

Я думаю, что одним из способов является предоставление уникального идентификатора разрешения каждому объекту (oranisation, муниципалитет, округ, штат)

Таким образом, в ваших таблицах должен быть новый столбец allow_id со следующей формой: Организация 1 будет иметь разрешение_1 O1 Организация 2 будет иметь идентификатор разрешения O2

Муниципалитет 1 будет иметь разрешение ID M1 Муниципалитет 2 будет иметь разрешение ID M2

и т. Д.

Затем вы можете создать таблицу разрешений (id, id_user, permissions) где столбец разрешений будет что-то вроде O1 - разрешение только для Организации1 М1 - разрешение для всех организаций в муниципалитете 1 M1M2 - разрешение для всех организаций в муниципалитетах 1 и 2

S1 - разрешение для государства 1

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

пример.

Вы находитесь на странице муниципалитета. M2. С пользователем, который имеет разрешение на S2 Ваша функция получит в качестве аргумента идентификатор муниципалитета, а функция создаст маршрут: M2, C3, S1. Затем вы сравниваете S2 с S1, и разрешение отклоняется. Таким образом, сложность составляет O (n), где n - это число организаций (организаций, муниципалитетов, округов и штатов, то есть 4).

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