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

Я часто сталкиваюсь со следующим сценарием, когда мне нужно предложить много разных типов разрешений. В основном я использую 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 [email protected]
      AND ([email protected] OR [email protected] OR
     (emp.UserID IS NULL AND dept.DeptID IS NULL)) AND ApplicationID = 1
    ORDER BY q.QID ASC
    

Мои мысли

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

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

Ответов (5)

Решение

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

Лично я иногда использую помеченное перечисление разрешений. Таким образом, вы можете использовать побитовые операции 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).

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

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

Например, приложение Доставка может сказать вам, что ему нужны:

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

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

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

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

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

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

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

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

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