Pull to refresh

Comments 16

А можно спросить, почему так все сложно?
Кто вам мешает понаделывать экстеншинов к контексту которые возвращают IQueryable?
Context.GetPermittedUsers();
Context.GetPermittedOrders(BusinessRole.Manager);

Все аккуратненько, в одном месте без дополнительных абстракций, глобальности, сайд эффектов и легко трекается решарпером.
Предложенный вами подход имеет преимущество: он более явный. С другой стороны вам придется теперь везде писать Context.GetPermittedUsers(). Как проконтролировать, что другой разработчик по ошибке не вызовет Context.Users? В варианте с дополнительным интерфейсом можно вообще не подключать EF к web-проекту и работать только через слой бизнес-логики. Еще на extension'ы не повесить декораторы.
Но ведь веб-проект является composition root, и подключить слой доступа для регистрации всего в DI контейнере всё равно придётся?

Если ну очень хочется, то регистрацию можно вынести в отдельную сборку и подключить к хосту уже ее. Бывает полезно, если хостов много. В общем случае вы правы.

Но ведь тепереь вам всюду придется вызвыавать QueryableProvider? Как вы этот контракт будете контролировать? Я бы во время code review просто глянул кто напрямую использует DbSet и почесал бы себя по затылку, а потом взял бы чесалку чтобы кого-то почесать.
Не усложняйте себе и другим жизнь. Все должно быть явно и легко трекаться средствами разработки.
Global filters, еще та палка о двух концах. Мило, но бесполезно. Отрубить фильтр может каждый, а вот оттрекать это нереально.

Что вы имеете в виду, когда говорите «оттрекать»?

Найти в каком месте фильтр был отключен для специфического DbSet.
Использование разных интерфейсов эту проблему решает на 100%: используете DbSet напрямую — фильтров нет. Используете абстракцию — фильтры есть. Если используете глобальные фильтры DbContext.Set<T>() — с фильтрами, DbContext.Set<T>().IgnoreQueryFilters() — без.
Я не специалист в EF, но насколько я знаю, прочитав их спецификацию, использование IgnoreQueryFilters отрубает фильтры во всем запросе. Поправьте меня если я не прав.
Для меня это выглядит как: мы вам даем сомнительную возможность отфильтровать гарантировано, но оставили лазейку. И кто-то таки выстрелит себе в ногу.

Как насчет нарезать доступ контролировано, я про свой сампл Context.GetPermittedOrders(BusinessRole.Manager)? Ваше же решение режет энтити на корню.

Имея большой опыт разработки, дам простой совет: чем проще, тем лучше. И в поддержке и в выявлении багов. Как раз разбираюсь с одним багом, который неявно вытекает из-за использования сомнительного решения по трансформациии дерева выражений перед отправкой его Query Provider. До сих пор теряюсь в догадках — зачем! Чем меньше динамики, тем приложение стабильнее.

Я в подобных случаях использую спецификации

Да, можно решать спецификациями, но это не гарантирует, что разработчик не забудет дописать queryable.Where(spec).

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


А что бы не забывать применить спецификации, давайте им понятные названия и объединяйте их в большие. Например, в вашем случае, можно создать спецификации ClientOrganizationsSpec и StaffingAgencyOrganizationsSpec и объединить в общую UserOrganizationsSpec.
Остальные правила которые вы описываете в Where, так же можно описать через спецификации и в результате в контроллере вы будете передавать 1-3 спецификации.


На мой взгляд, проще ориентироваться в наборе спецификаций имеющих четкое название и четкое назначение чем в куче условий в Where. Тем более что со спецификациями вы уже имели дело. Кстати говоря, как ваше впечатление от них спустя год?

Вообще, ограничения доступа которые вы описали в статье, это больше похоже на бизнесовые правила и им место скорее в спецификациях, а не на глобальном уровне. Применяя их на глобальном уровне вы можете столкнутся с ситуацией когда вам нужно получить данные не применяя эти правила.
Да и тогда нужно будет обращаться к другому контексту, который возвращает не «отфильтрованный» IQueryable. Кроме того этот случай решается «супер-пользователем», который видит все и может логиниться от имени кого угодно. Де-факто такой пользователь почти всегда появляется:)

На самом деле ничего не мешает использовать спецификации внутри таких фильтров. Я просто не стал усложнять код в примере.
На мой взгляд, проще ориентироваться в наборе спецификаций имеющих четкое название и четкое назначение чем в куче условий в Where. Тем более что со спецификациями вы уже имели дело.
Да, но если эти данные вообще не предназначены для данного пользователя зачем ему вообще иметь возможность их видеть? Неявность имеет не только плохую, но и хорошую сторону. В некоторых случаях хорошо, что прикладной разработчик не заботится о доступе. Снижает нагрузку на мозг.

Кстати говоря, как ваше впечатление от них спустя год?
Короткий ответ — отлично. Если хотите длинный ответ, то <a href=«www.youtube.com/watch?v=DD3w66Ff8Ms&t=948s.
Кроме того этот случай решается «супер-пользователем»

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


  • Персональный пользователь с правами администратора – Да
  • Временный пользователь для функциональных тестов – Да
  • Пользователь с ограниченными правами для ботов – Да

Но не супер-пользователь.


Да, но если эти данные вообще не предназначены для данного пользователя зачем ему вообще иметь возможность их видеть?

Моё предложение в том, что бы использовать базовую спецификацию проверяющую права и расширять её при необходимости. В этом случае вы в явном виде запрашиваете данные конкретного пользователя. То есть, это не спецификация проверчющая права доступа, а спецификация возвращающая пользовательские данные, которая инкапсулирует проверку прав доступа. Это немного другой взгляд.


Конечно можно применять фильтры и на глобальном уровне в неявном виде. Иногда я тоже так делаю, но лично я все равно придерживаюсь мнения, что явное лучше неявного.


Короткий ответ — отлично. Если хотите длинный ответ, то вот он.

Спасибо за доклад. Было интересно послушать.

В своей практике я не припомню случаев необходимости в таких пользователях.

Техподдержка Azure или YouTrack, например, чудесным образом имеет доступ к моим данным в облаке и помогает решать проблемы, когда что-то не работает;)

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

Sign up to leave a comment.

Articles