Каков наилучший способ обработки нескольких типов разрешений?

Я часто сталкиваюсь со следующим сценарием, где мне нужно предложить множество разных типов разрешений. Я в основном использую ASP.NET / VB.NET с SQL Server 2000.

сценарий

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

В прошлом я выбрал один из следующих двух способов, которые я знаю, чтобы сделать это.

1) Используйте единую таблицу разрешений со специальными столбцами, которые используются для определения того, как применять параметры. Специальные столбцы в этом примере – TypeID и TypeAuxID. SQL будет выглядеть примерно так.

SELECT COUNT(PermissionID) FROM application_permissions WHERE (TypeID = 1 AND TypeAuxID = @UserID) OR (TypeID = 2 AND TypeAuxID = @DepartmentID) AND ApplicationID = 1 

2) Используйте таблицу сопоставлений для каждого типа разрешений, а затем объедините их все вместе.

 SELECT COUNT(perm.PermissionID) FROM application_permissions perm LEFT JOIN application_UserPermissions emp ON perm.ApplicationID = emp.ApplicationID LEFT JOIN application_DepartmentPermissions dept ON perm.ApplicationID = dept.ApplicationID WHERE q.SectionID=@SectionID AND (emp.UserID=@UserID OR dept.DeptID=@DeptID OR (emp.UserID IS NULL AND dept.DeptID IS NULL)) AND ApplicationID = 1 ORDER BY q.QID ASC 

Мои мысли

Надеюсь, что примеры имеют смысл. Я собрал их вместе.

Первый пример требует меньше работы, но ни один из них не чувствует себя лучшим ответом. Есть ли лучший способ справиться с этим?

Я согласен с Джоном Дауни.

Лично я иногда использую перечисление разрешений с флагом. Таким образом вы можете использовать AND, OR, NOT и XOR побитовые операции над элементами перечисления.

 "[Flags] public enum Permission { VIEWUSERS = 1, // 2^0 // 0000 0001 EDITUSERS = 2, // 2^1 // 0000 0010 VIEWPRODUCTS = 4, // 2^2 // 0000 0100 EDITPRODUCTS = 8, // 2^3 // 0000 1000 VIEWCLIENTS = 16, // 2^4 // 0001 0000 EDITCLIENTS = 32, // 2^5 // 0010 0000 DELETECLIENTS = 64, // 2^6 // 0100 0000 }" 

Затем вы можете объединить несколько разрешений с помощью битового оператора AND.

Например, если пользователь может просматривать и редактировать пользователей, двоичный результат операции – 0000 0011, который преобразуется в десятичный, равен 3.
Затем вы можете сохранить разрешение одного пользователя в один столбец вашей базы данных (в нашем случае это будет 3).

Внутри приложения вам просто нужна другая побитовая операция (OR), чтобы проверить, имеет ли пользователь определенное разрешение или нет.

Как правило, я использую системы разрешений для кодирования, имеет 6 таблиц.

  • Пользователи – это довольно прямолинейно, это ваша типичная таблица пользователей
  • Группы – это будет синонимом ваших отделов
  • Роли – это таблица со всеми разрешениями, как правило, также включая читаемое человеком имя и описание
  • Users_have_Groups – это таблица «многие-ко-многим» групп, к которым принадлежит пользователь.
  • Users_have_Roles – другая таблица «многие-ко-многим», роли которой назначаются отдельному пользователю
  • Groups_have_Roles – окончательная таблица «многие-ко-многим», какие роли каждая группа имеет

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

Как я уже сказал, это то, что я обычно делаю, но ваш размер может отличаться.

В дополнение к решениям John Downey и jdecuyper я также добавил бит «Явный отказ» в конце / начале бит-бита, чтобы вы могли выполнять аддитивные разрешения по группам, членству в ролях, а затем вычитать разрешения на основе явного отказа записи, как и NTFS, разрешено.

Честно говоря, функции членства / роли ASP.NET отлично работали бы для описанного вами сценария. Написание собственных таблиц / procs / classes – отличное упражнение, и вы можете получить очень хороший контроль над мельчайшими подробностями, но после этого я пришел к выводу, что лучше всего использовать встроенный материал .NET. Много существующего кода предназначено для работы вокруг него, что хорошо хорошо. Написание с нуля заняло у меня около 2 недель, и это было не так удобно, как .NET. Вы должны кодировать так много дерьма (восстановление пароля, автоматическая блокировка, шифрование, роли, интерфейс разрешений, тонны procs и т. Д.), И время может быть лучше потрачено в другом месте.

Извините, если я не ответил на ваш вопрос, я как парень, который говорит, чтобы узнать c #, когда кто-то задает вопрос vb.

Подход, который я использовал в различных приложениях, состоит в том, чтобы иметь общий класс PermissionToken, который имеет изменяемое свойство Value. Затем вы запрашиваете запрошенное приложение, оно сообщает вам, какие PermissionTokens необходимы для его использования.

Например, приложение «Доставка» может сказать вам, что это необходимо:

 new PermissionToken() { Target = PermissionTokenTarget.Application, Action = PermissionTokenAction.View, Value = "ShippingApp" }; 

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