Я часто сталкиваюсь со следующим сценарием, когда мне нужно предложить много разных типов разрешений. В основном я использую ASP.NET / VB.NET с SQL Server 2000.
Сценарий
Я хочу предложить систему динамических разрешений, которая может работать с разными параметрами. Допустим, я хочу предоставить доступ к приложению отделу или только конкретному человеку. И представьте, что у нас есть ряд приложений, которые продолжают расти.
В прошлом я выбрал один из двух известных мне способов сделать это.
Используйте единую таблицу разрешений со специальными столбцами, которые используются для
определение того, как применять параметры. Специальные столбцы в
этот пример - TypeID и TypeAuxID. SQL будет смотреть что-нибудь
так.
SELECT COUNT(PermissionID)
FROM application_permissions
WHERE
(TypeID = 1 AND TypeAuxID = @UserID) OR
(TypeID = 2 AND TypeAuxID = @DepartmentID)
AND ApplicationID = 1
Используйте таблицу сопоставления для каждого типа разрешений, а затем присоединитесь к ним все вместе.
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
Мои мысли
Я надеюсь, что эти примеры имеют смысл. Я сколотил их вместе.
Первый пример требует меньше усилий, но ни один из них не кажется лучшим ответом. Есть ли лучший способ справиться с этим?


Я обычно использую системы разрешений для кодирования с 6 таблицами.
В начале пользовательского сеанса вы должны запустить некоторую логику, которая извлекает каждую роль, которую они назначили, либо через каталог, либо через группу. Затем вы кодируете эти роли в качестве разрешений безопасности.
Как я уже сказал, это то, что я обычно делаю, но ваш стиль может отличаться.
Подход, который я использовал в различных приложениях, состоит в том, чтобы иметь общий класс PermissionToken с изменяемым свойством Value. Затем вы запрашиваете запрошенное приложение, оно сообщает вам, какие PermissionTokens необходимы для его использования.
Например, приложение Доставка может сказать вам, что ему нужны:
new PermissionToken()
{
Target = PermissionTokenTarget.Application,
Action = PermissionTokenAction.View,
Value = "ShippingApp"
};
Это, очевидно, может быть расширено до Create, Edit, Delete и т. д., И благодаря настраиваемому свойству Value любое приложение, модуль или виджет может определять свои собственные необходимые разрешения. YMMV, но для меня это всегда был эффективный метод, который, как я обнаружил, хорошо масштабируется.
Я согласен с Джоном Дауни.
Лично я иногда использую помеченное перечисление разрешений. Таким образом, вы можете использовать побитовые операции 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).
Внутри вашего приложения вам просто нужна другая побитовая операция (ИЛИ), чтобы проверить, есть ли у пользователя конкретное разрешение или нет.
В дополнение к решениям Джона Дауни и jdecuyper я также добавил бит «Явное запрещение» в конце / начале битового поля, чтобы вы могли выполнять дополнительные разрешения по группам, членству в ролях, а затем вычитать разрешения на основе явного отказа Записи, как и NTFS, работают с разрешениями.
Честно говоря, функции членства / ролей ASP.NET идеально подходят для описанного вами сценария. Написание собственных таблиц / процедур / классов - отличное упражнение, и вы можете получить очень хороший контроль над мельчайшими деталями, но, сделав это сам, я пришел к выводу, что лучше просто использовать встроенные в .NET вещи. Большая часть существующего кода предназначена для обхода этого, что хорошо получается. Написание с нуля заняло у меня около 2 недель, и это было далеко не так надежно, как .NET. Вам нужно кодировать так много чуши (восстановление пароля, автоматическая блокировка, шифрование, роли, интерфейс разрешений, множество процедур и т. д.), И время можно было бы лучше потратить в другом месте.
Извините, если я не ответил на ваш вопрос, я похож на парня, который говорит изучать C#, когда кто-то задает вопрос vb.
Проблема, которую я обнаружил при таком подходе, заключается в том, что при таком подходе очень легко исчерпать все роли. Как видите, 6 ролей имеют значение 2 ^ 6 = 64, тогда как 31 роль будет иметь 2 ^ 31 = 2 147 483 647, что является максимальным значением int. Итак, в T-SQL самый большой тип данных, который можно использовать, - это
bigint(2 ^ 63). Конечно, вы можете использовать тип varchar, но я предпочитаю использовать решение Джона Дауни, когда у меня много ролей.