Реферат: Row-Level Security в РСУБД
Если же СУБД не предоставляет средств поддержки групп или ролей, то их тоже придется реализовывать вручную. Одним из простейших способов является создание специальной таблицы, содержащей список групп или ролей, и связь ее с таблицей пользователей. В зависимости от потребностей, можно выбрать различные схемы. Если пользователь может входить только в одну группу, то достаточно добавить ссылку на группу в таблицу пользователей. А если ему может быть назначено одновременно несколько ролей, то для связи надо будет создать отдельную таблицу.
В таких случаях предикат IsUserInRole(rolename) принимает вид:
exists(select * from users where ID = CurrentUserID() and user_group = rolename) |
или
exists(select * from UserRoles where RoleName = rolename and UserID = CurrentUserID()) |
В дальнейшем мы будем подразумевать под выражением IsUserInRole(rolename) либо подходящую встроенную функцию СУБД, либо предикат, построенный вручную в соответствии с выбранной моделью.
Ограничения на основе существующих атрибутов
Если правила корпоративной политики выражаются в терминах предметной области, то можно сформировать соответствующий предикат безопасности в терминах данных, хранимых в СУБД.
В самом простом случае достаточно данных из той же таблицы. Предположим, доступ к еженедельным документам финансовой отчетности компании определяется следующими правилами:
младшие финансовые аналитики имеют право чтения отчетов старше шести месяцев;
старшие финансовые аналитики имеют право чтения отчетов старше одного месяца;
всем остальным сотрудникам доступ к документам запрещен.
В таком случае можно построить примерно такой предикат:
(IsUserInRole('senior_analyst') and ReportDate < DateAdd(month, GetDate(), 1)) OR (IsUserInRole('junior_analyst') and ReportDate < DateAdd(month, GetDate(), 6)) |
В принципе, тот же самый результат можно получить и другими способами. Например, вот такое выражение SQL отражает те же самые правила:
case when ReportDate > DateAdd(month, GetDate(), 1) then false when ReportDate > DateAdd(month, GetDate(), 6) then IsUserInRole('senior_analyst') else IsUserInRole('junior_analyst') end |
Однако здесь проследить логику уже труднее, и ситуация станет еще хуже, когда в рассмотрение войдут другие поля таблицы. Поэтому мы ограничим возможные предикаты вот такой структурой:
(IsUserInRole(<role1>) AND <role1_restrictions>) OR (IsUserInRole(<role2>) AND <role2_restrictions>) OR ... (IsUserInRole(<roleN>) AND <roleN_restrictions>) |