Планируется, что будут существовать разные группы пользователей. Некоторым группам будут доступны одни элементы, другим другие, третьим часть одних и чать других. (Где-то кнопка от других скрыта, где-то меню недоступно).
Как это правильнее сделать? Как это вообще делают?
Здравствуйте, Cokkab, Вы писали:
C> Планируется, что будут существовать разные группы пользователей. C> Некоторым группам будут доступны одни элементы, другим другие, третьим C> часть одних и чать других. (Где-то кнопка от других скрыта, где-то меню C> недоступно). C> C> Как это правильнее сделать? Как это вообще делают?
В одном из своих проектов мы делали следующим образом:
Права разграничиваются по следующим элементам интерфейса: пункты меню, элементы управления. С каждым элементом интерфейса связывается строка вида "<acl=128>", которая обозначает битовую маску, необходимую для доступности этого элемента управления пользователю. У текущего пользователя есть "эффективный" acl, который обозначает его текущие права. С элементами интерфейса строку можно связать либо через поле Tag (есть практически во всех RAD), либо через SetProp/GetProp для окошек и контролов. Для меню — в структурах MENUINFO и MENUITEMINFO есть пользовательские поля, можно там хранить.
Еще есть объект-синглетон и у него, в частности, две функции. Одна, условно говоря, принимает HWND, другая HMENU. Функция пробегает рекурсивно по всем дочерним узлам (подменю или подокнам) и для всех элементов достает строку вида <acl=128>, делает and с текущими правами пользователя, сравнивает с acl. Соответственно делает enabled/disabled. В общем, стандартный активатор. Принцип, думаю, понятен? Детали не разжевываю.
Для нас работает, YMMV.
-- Всего хорошего!
-- Alex Alexandrov, e-mail: alexandrov_alex@fromru.com
Posted via RSDN NNTP Server 1.7 beta
It's kind of fun to do the impossible (Walt Disney)
Здравствуйте, mikkri, Вы писали:
m> Здравствуйте, alexandrov_alex, m> m> только возможное количество ролей пользователя у тебя ограничивается m> длиной твоей маски
Да, я знаю. Я осознанно на это пошел. Реализация упрощается. Битов пока хватает, если не хватит — будем думать. Конечно, такой подход не сгодится в случае приложения с заведомо неизвестным количеством привилегий — например, если есть конструктор форм, и пользователь может сам создавать привилегии.
-- Всего хорошего!
-- Alex Alexandrov, e-mail: alexandrov_alex@fromru.com
Posted via RSDN NNTP Server 1.7 beta
It's kind of fun to do the impossible (Walt Disney)
Здравствуйте, alexandrov_alex, Вы писали:
_>Здравствуйте, mikkri, Вы писали:
m>> Здравствуйте, alexandrov_alex, m>> m>> только возможное количество ролей пользователя у тебя ограничивается m>> длиной твоей маски _>Да, я знаю. Я осознанно на это пошел. Реализация упрощается. Битов пока хватает, если не хватит — будем думать. Конечно, такой подход не сгодится в случае приложения с заведомо неизвестным количеством привилегий — например, если есть конструктор форм, и пользователь может сам создавать привилегии.
Ну это уже будет перебор, скорее всего.
Все же количество ролей у пользователей определяется не сложностью форм, а бизнес-процессами и штатным расписанием компании.
Здравствуйте, Cokkab, Вы писали:
C>Как это правильнее сделать? Как это вообще делают?
Ну теория в общем то простая — существуют два способа задания прав.
1) По пользователям. В этом случае каждому объекту, на который нужно задавать права, ставится в соответствие список пользователей, имеющих к нему доступ. Если объект имеет несколько уровней доступа то, помимо собственно идентификатора пользователя, указывается уровень доступа.
2) По ролям. Вводится некая сущность, называемая ролью. Права и уровни доступа на объекты назначаются не пользователям, а ролям. А пользователям назначается список ролей.
Собственно и вся теория. Сложность в практике.
На практике подход 1 в чистом виде как правило не применяют, разве что пользователей совсем мало ( < 10). Подход 2 является простейшим вариантом и частенько применяется там где разработчикам не хватило желания или средств реализовывать полноценную защиту, либо структура защищаемых данных проста. В более-менее приличных системах используется комбинация обоих подходом, т.е. в списке доступа объекта могут присутствовать как роли так и конкретные пользователи.
Главная же сложность в собственно контроле. Здесь надо определиться прежде всего с минимальным объектом, по которому необходимо контролировать права. Понятно что заказчик чаще всего будет требовать очень низкий уровень задания прав, частенько народ очень хочет чтобы права контролировались по кждой записи таблицы. К сожалению такой уровень контроля для современных железок не приемлем из-за слишком высоких накладных расходов. Так что здесь надо искать золотую середину между атомарностью контроля и потерями производительности.
Вот придумал я такой пример, который наиболее качественно отображает мою цель:
Есть форма, на этой форме два контрола: кнопка и комбобокс
Существует событие — нажатие на кнопку.
Это событие должно выполниться если:
1. Текущему пользователю разрешено это сделать;
2. Значение комбобокса равно X;
Причем значение X зависит от текущего пользователя, т.е. для каждого пользователя существует своё значение X при котором событие может выполниться.
После выполнения события, в зависимости от пользователя для комбобокса устанавливается значение.
Вот такая вот беда. Т.е. получается, что модель не объектная, а событийная.
Кто-нибудь видел существующие решения такого плана проблем?
Здравствуйте, Cokkab, Вы писали:
C>Существует событие — нажатие на кнопку. C>Это событие должно выполниться если: C>1. Текущему пользователю разрешено это сделать; C>2. Значение комбобокса равно X;
Попытка назначать права исходя из пользовательского интерфейса изначально неверный подход. Попытка определять права исходя из вычисления каких то формул как правило неприе6млема из-за слишком низкой производительности.
Здравствуйте, AndrewVK, Вы писали:
A> Здравствуйте, Cokkab, Вы писали: A> C>> Существует событие — нажатие на кнопку. C>> Это событие должно выполниться если: C>> 1. Текущему пользователю разрешено это сделать; C>> 2. Значение комбобокса равно X; A> A> Попытка назначать права исходя из пользовательского интерфейса A> изначально неверный подход. Попытка определять права исходя из A> вычисления каких то формул как правило неприе6млема из-за слишком низкой A> производительности.
Почему? В данном случае человек описывает довольно типичный сценарий: есть некий граф состояний, переход по которому может осуществляться несколькими путями, в зависимости от роли пользователя. Например, система отслеживания версий. Есть поле — состояние Change Request. Все могут наблюдать текущее состояние CR, но только некоторые могут его переводить, например, из состояния Submitted в состояние Closed. Я бы в данном случае не привязывался вообще к UI. Надо попытаться определить этот граф, идентифицировать возможные состояния, и одной таблицы должно хватить для описания этой схемы. Что-то типа:
— идентификатор роли (или пользователя, в зависимости от выбранной схемы)
— идентификатор начального состояния.
— идентификатор следующего состояния.
Тогда в диалоге пользователь может изменять значение поля, только если в этой таблице для него есть строка (строки) с текущим состоянием. Причем выбрать он сможет только одно из тех состояний, которые указаны для него в поле "Идентификатор следующего состояния".
-- Всего хорошего!
-- Alex Alexandrov, e-mail: alexandrov_alex@fromru.com
Posted via RSDN NNTP Server 1.7 beta
It's kind of fun to do the impossible (Walt Disney)
Здравствуйте, alexandrov_alex, Вы писали:
_>Почему?
Потому что
1) Защита интерфейса это и не защита вовсе. Защищать надо собственно данные и алгоритмы их обработки.
2) Нередко один объект может иметь более чем один интерфейс.
3) Интерфейс как правило меняется чаще чем объекты предметной области.
... Пропущено ... A> Потому что A> 1) Защита интерфейса это и не защита вовсе. Защищать надо собственно A> данные и алгоритмы их обработки. 2) Нередко один объект может иметь A> более чем один интерфейс. 3) Интерфейс как правило меняется чаще чем A> объекты предметной области.
Видимо, ты не совсем понял, что я хотел сказать. Никто не спорит, что надо защищать данные. Никто не спорит, что в выше описанном мной примере смена состояний должна осуществляться из одного места — желательно хранимой процедуры, или application server в том или ином его проявлении. Я говорю, что описанный сценарий не является нетипичным. И элементы интерфейса придется дизаблить-енаблить. Иначе это фигня, а не программа.
-- Всего хорошего!
-- Alex Alexandrov, e-mail: alexandrov_alex@fromru.com
Posted via RSDN NNTP Server 1.7 beta
It's kind of fun to do the impossible (Walt Disney)
По-моему, то, что ты описал не относится к разграничениям прав доступа, а относится скорее к бизнес-логике. Прикрутить такие ограничения к системе прав, имхо, не стоит пытаться, если только ты не в какой-то весьма специфичной предметной области...
Здравствуйте, alexandrov_alex, Вы писали:
_>Видимо, ты не совсем понял, что я хотел сказать. Никто не спорит, что надо защищать данные. Никто не спорит, что в выше описанном мной примере смена состояний должна осуществляться из одного места — желательно хранимой процедуры, или application server в том или ином его проявлении. Я говорю, что описанный сценарий не является нетипичным. И элементы интерфейса придется дизаблить-енаблить. Иначе это фигня, а не программа.
Дизаблить их придется, с этим никто не спорит. Но в примере интерфейс ИСПОЛЬЗОВАЛСЯ для определения прав доступа.
> Не понимаю, что значит "ИСПОЛЬЗОВАЛСЯ для определения прав доступа".
Поясняю, это следует из фразы: C>2. Значение комбобокса равно X;
Хотя на самом деле нужно определять требование основываясь не на значении
комбобокса, а на состоянии объекта, которое отображает комбобокс. А с точки
зрения пользователя это одно и то же.
A>По-моему, то, что ты описал не относится к разграничениям прав доступа, а относится скорее к бизнес-логике. Прикрутить такие ограничения к системе прав, имхо, не стоит пытаться, если только ты не в какой-то весьма специфичной предметной области...
Да, согласен. Не правильно назвал тему.
Целью является конечно же не защита, а управление пользовательским интерфейсом — одному одно показать, другому другое.