Я перепробовал множество различных схем для разрешений, и я когда-либо нашел только один способ заставить их работать, который удовлетворяет программиста И клиентов почти во всех случаях. И это делает их частично управляемыми данными.
Моя последняя попытка работает так:
- Каждый пользователь имеет прикрепленный к нему объект прав доступа. В моем случае создается автоматически при запросе пользователя. (В моем случае разрешения могут быть разными для разных разделов. Поэтому пользователю может быть разрешено делать X для Y, но не для Z.)
- Каждая страница, блок кода или представление, которое должно быть разрешающим, заключено в оператор if, который проверяет объект разрешения. Если это разрешение должно беспокоить и раздел, то текущие соответствующие идентификаторы раздела передаются в виде массива, возвращая новый массив bools для сопоставления.
- Интерфейс тогда не раскрывает этот сложный беспорядок непосредственно пользователям, вместо этого интерфейс superadmin позволяет создавать новые типы пользователей. Эти типы несут наборы разрешений, которые будут включены для этого «типа» пользователя. Разрешения разных типов могут перекрываться, поэтому как администратор, так и редактор могут «редактировать копию» или что-либо подобное.
- Нормальный интерфейс администратора позволяет отдельным пользователям назначаться разными типами пользователей для разных разделов. Таким образом, один пользователь может быть администратором для раздела 2 и редактором для разделов 2, 3, 4 и 5. Они также могут быть установлены глобально, что перегружает неиспользуемый раздел (0).
Это имеет много преимуществ и один недостаток. Во-первых, недостаток. Поскольку эти ключи запекаются непосредственно в коде, только суперадмин (он же разработчик) должен иметь доступ к этой части интерфейса. Действительно, интерфейс может вообще не понадобиться, так как список разрешений должен меняться только с кодом. Настоящая проблема здесь в том, что вы не будете знать, что с заголовком что-то не так, пока не запустите код, так как синтаксис будет просто отличным. Теперь, если бы это было закодировано в чем-то вроде C #, это было бы очень серьезной проблемой. Но практически все в PHP не является типобезопасным, поэтому на самом деле это просто номинал для курса. Эти значения также могут быть загружены из файла конфигурации или даже запрограммированы в графическом интерфейсе, из которого вы строите пользовательские типы, хотя это кажется неправильным.
Что вы получаете от этого, так это возможность устанавливать новые типы разрешений на лету. Вы получаете возможность переименовывать эти разрешения с относительной легкостью. (Поскольку система просто использует номер, заголовок используется только для захвата номера, поэтому его можно легко изменить всего в нескольких местах.) И код очень прост в использовании. Это будет выглядеть примерно так:
if($current_user->permissions->can("View Sales Records"))
{
//Code to view sales records
}
Или немного сложнее
$sections = array(1,2,3,4); //Probably really a list of all sections in the system
$section_permissions = $current_user->permissions->these($sections)->can("Edit Section");
foreach($sections as $s)
{
if($section_permissions[$s])
{
// Code for maybe displaying a list of sections to edit or something
}
}
Метод цепочки также довольно прост. ->these()
устанавливает внутренний массив для этих значений и затем возвращает ссылку на сам объект. ->can()
затем действует в этом списке, если он существует, и затем отменяет его. В моей собственной версии у меня также есть ->any()
, который всегда возвращает полный список разделов, поэтому я могу проверить ->any()->can()
.
Наконец, объект прав доступа также содержит список типов пользователей. Что позволяет действительно легко показать список пользователей и какие разрешения у них активны. В моем случае мы просто используем ->types()
для доступа к этому списку и массиву ids => names
.
Отсутствующие заголовки разрешений просто игнорируются. Они также сопоставляются в нижнем регистре с удаленными пробелами и специальными символами, чтобы помочь уменьшить проблемы с ошибками ввода Я подумал даже сделать проверку расстояния Левенштейна и выбрать ближайший матч. Но, в конце концов, лучше не полагаться на что-то подобное. (возможно зарегистрируйте ошибку, но изящно выберите ближайшее совпадение.)
Вне кода и в интерфейсе пользователям необходимо только общаться друг с другом в «Со-в-так» - это «Администратор», «Редактор», «Издатель», «Автор» и «Генеральный директор» и так далее. Также было бы тривиально создавать разные наборы пользовательских типов для разных организаций.
Все части этого могут быть сильно кэшированы, настройка простого пользователя для людей, которые вообще не вошли в систему, очень проста, и мне еще предстоит столкнуться с проблемой на основе разрешений, которая не очевидна для решить с помощью этой структуры.
Я только хотел бы поделиться с вами настоящим кодом. Я просто не владею им и поэтому не могу опубликовать это.