Защита / пропуск выбранных свойств объекта домена в NHibernate (подкласс, проекция,?) - PullRequest
2 голосов
/ 07 сентября 2010

Рассмотрим следующий упрощенный сценарий:

public class Person
{
    public string Name { get; set; }

    public int Age { get; set; }

    // restricted
    public string SocialSecurityNumber { get; set; }

    // restricted
    public string MothersMaidenName { get; set; }
}

Итак, в приложении многие пользователи могут просматривать Person данные. Некоторые пользователи могут просматривать все; другие пользователи могут просматривать только Name и Age.

Наличие на пользовательском интерфейсе только авторизованных данных достаточно просто на стороне клиента, но я действительно не хочу даже отправлять эти данные клиенту.

Я пытался достичь этого путем создания иерархии FullPerson : BasicPerson (таблица-на-класс-иерархия). Я использовал две реализации StaffRepository для получения желаемого типа, но необходимое приведение не выполняется во время выполнения из-за прокси-серверов NH. Конечно, в РСУБД любая заданная строка в таблице People может представлять FullPerson или BasicPerson, и присвоение им обоих одинакового значения дискриминатора также не работает.

Я рассмотрел только отображение FullPerson и использование преобразователя результата AliasToBean для фильтрации до BasicPerson, но я понимаю, что это улица с односторонним движением, тогда как я хочу в полной мере воспользоваться преимуществами управления объектами и отложенной загрузки хотя приведенный выше пример не включает коллекции) в сеансе.

Еще одна мысль, которую я имел, заключалась в том, чтобы обернуть все ограниченные поля в класс и добавить это как свойство. Мои проблемы с этим подходом несколько:

  1. Это ставит под угрозу мою модель домена,
  2. Мне нужно было бы объявить свойство как коллекцию (всегда 1), чтобы оно загружалось лениво, и
  3. Я даже не уверен, как бы предотвратить загрузку этой ленивой коллекции.

Все это кажется неправильным. Есть ли известный подход для достижения желаемого результата?

пояснение:

Это в настольном приложении только для интрасети; сеанс живет на клиенте. Хотя я, конечно, могу создать промежуточный уровень обслуживания, мне придется отказаться от отложенной загрузки и отслеживания изменений, которые я действительно хотел бы сохранить на месте.

Ответы [ 2 ]

2 голосов
/ 07 сентября 2010

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

Я бы вставил слой в сервис или контроллер, который получает этот запрос данных от клиента (который не должен быть репозиторием).сам) и будет выполнять редактирование данных на основе разрешений пользователей.Таким образом, вы выполняете полный запрос к БД, а затем, основываясь на разрешениях пользователя, сервисный уровень очищает поля набора результатов перед возвратом этого набора результатов через соединение службы.Это не самое эффективное решение, но оно более безопасное и более производительное, чем отправка всех данных клиенту и наличие «цензуры» клиентского программного обеспечения.Соединение Ethernet между БД и сервисными уровнями серверной архитектуры может обрабатывать гораздо большую пропускную способность, чем интернет-соединение между сервисным уровнем и клиентом, и в приложении удаленного клиента вы, как правило, очень мало контролируете, что клиент делает с данными;вы могли бы разговаривать со взломанной копией вашего программного обеспечения или аналогом, который не дает двух замечаний по поводу безопасности пользователя.

Если пропускная способность сети между службой и БД имеет большое значение, или если многоинформация ограничена, Linq2NH должен быть достаточно умным, чтобы вы могли указать, что следует или не следует включать в результаты запроса, используя список выбора:

if(!user.CanSeeRestrictedFields)
   var results = from p as Repository.AsQueryable<Person>()
   //rest of Linq statement
   select new Person { 
         Name = p.Name,
         Age = p.Age
      };
else
   var results = from p as Repository.AsQueryable<Person>()
   //rest of Linq statement
   select new Person { 
         Name = p.Name,
         Age = p.Age,
         SocialSecurityNumber = p.SocialSecurityNumber,
         MothersMaidenName = p.MothersMaidenName
      };

Я не знаю, достаточно ли умна Linq2NH для анализаусловные операторы в SQL;Я сомневаюсь в этом, но на случай, если это возможно, вы можете указать условные операторы в инициализаторе для полей SSN и MMN в зависимости от того, есть ли у пользователя права на их просмотр, что позволяет объединить эти два запроса.

2 голосов
/ 07 сентября 2010

Я бы оставил модель вашего домена в покое, и вместо этого использовал бы Automapper для сопоставления с определенными DTO на основе уровня безопасности текущего пользователя (или любых других критериев, которые вы используете для определения доступа к определенным свойствам). Это должно быть сделано на каком-то уровне обслуживания, который находится между вашим пользовательским интерфейсом и вашими репозиториями.

Edit:

Исходя из ваших требований по сохранению отложенной загрузки и отслеживанию изменений, возможно, использование прокси-шаблона для переноса объекта вашего домена является жизнеспособной альтернативой? Вы могли бы обернуть свою исходную модель домена в прокси, который выполнял ваши проверки безопасности для каждого данного свойства. Я считаю, что CSLA.NET использует такой метод для обеспечения безопасности на уровне поля, поэтому, возможно, стоит поискать источник, чтобы получить некоторое вдохновение. Возможно, вы могли бы сделать еще один шаг вперед и использовать интерфейсы, реализованные вашим прокси, которые открывали только те свойства, к которым у пользователя был доступ.

...