Управление разрешениями пользователей с помощью иерархии

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

Пример иерархии

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

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

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

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

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

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

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

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

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

Я бы предложил создать в вашей базе несколько групп пользователей, каждая из которых имеет в себе один или несколько уровней учетной записи пользователя, а затем присваивает целочисленное значение как иерархическое значение для группы, а затем делает то же самое для отдельных уровней аккаунта в группе , что-то вроде этого (это реляционная структура, используйте 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 

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

 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. ); 

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

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

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

и так далее.

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

S1 – разрешение для состояния 1

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

пример.

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