Comments 21
А зачем изобретать велосипед?
Рекомендую почитать на тему: Role Based Security и Access List Based Security
Ваш пример это от не знания ни того, ни другого.
ASP.NET реализовано Role Based Security
Таким образом, что что вы показали делается так:
1. Создаёте роли Editor, Viewer, или даже ContollerName_ActionName (так кстати, SharePoint делает местами)
2. Добавляете пользователям те или иные роли
3. И вешаете аттрибут Authorize(Roles = «Editor, Viewer»)
И проблема решена.
В качестве домашнего задания вспомните алгебру и логические операции AND, OR…
10101 & 00100 == 00100
Это начало для реализации ACL based security.
Рано вам ещё статьи писать, сударь.
Рекомендую почитать на тему: Role Based Security и Access List Based Security
Ваш пример это от не знания ни того, ни другого.
ASP.NET реализовано Role Based Security
Таким образом, что что вы показали делается так:
1. Создаёте роли Editor, Viewer, или даже ContollerName_ActionName (так кстати, SharePoint делает местами)
2. Добавляете пользователям те или иные роли
3. И вешаете аттрибут Authorize(Roles = «Editor, Viewer»)
И проблема решена.
В качестве домашнего задания вспомните алгебру и логические операции AND, OR…
10101 & 00100 == 00100
Это начало для реализации ACL based security.
Рано вам ещё статьи писать, сударь.
+2
Позволю себе не согласиться. Автор упомянул RBS в самом начале и справедливо заметил, что все политики доступа определяются на этапе компиляции, что вы, собственно, и повторили в своем комментарии.
Идея статьи в том, чтобы показать способ задания политик «на лету». Например: сегодня к моим фотографиям имеют доступ «друзья» и «семья», а завтра я хочу, чтобы их видела только «семья». Если реализовывать это поведение в статике, то мне придется завести псевдо-роль «тот-кто-смотрит-фотографии», повесить ее на Action или весь Controller, а потом добавить ее ролям «друзья» и «семья», чтобы в нужный момент удалить ее из «друзей».
Так вот, чтобы не замусоривать код все новыми и новыми псевдо-ролями в разных местах, есть смысл вынести всю работу в отдельный класс, который будет содержать всю логику прав доступа. Например, внутри будет хэш-таблица, наполняемая из базы данных, в которой сегодня будет указано, что для контроллера фотоальбома есть две роли доступа («друзья» и «семья»), а завтра я уберу из базы данных «друзей» и все заработает так, как мне нужно.
Конечно, такой подход имеет свои недостатки. Самый главный — это рассинхронизация между физическим расположением Controller/Action и правилами доступа для них. Второй по важности — не все правила можно вынести в базу данных, поэтому время от времени этот класс придется переписывать.
Но, в целом, такой подход имеет полное право на существование и, насколько я знаю, используется многими, причем необязательно на платформе от Microsoft.
Идея статьи в том, чтобы показать способ задания политик «на лету». Например: сегодня к моим фотографиям имеют доступ «друзья» и «семья», а завтра я хочу, чтобы их видела только «семья». Если реализовывать это поведение в статике, то мне придется завести псевдо-роль «тот-кто-смотрит-фотографии», повесить ее на Action или весь Controller, а потом добавить ее ролям «друзья» и «семья», чтобы в нужный момент удалить ее из «друзей».
Так вот, чтобы не замусоривать код все новыми и новыми псевдо-ролями в разных местах, есть смысл вынести всю работу в отдельный класс, который будет содержать всю логику прав доступа. Например, внутри будет хэш-таблица, наполняемая из базы данных, в которой сегодня будет указано, что для контроллера фотоальбома есть две роли доступа («друзья» и «семья»), а завтра я уберу из базы данных «друзей» и все заработает так, как мне нужно.
Конечно, такой подход имеет свои недостатки. Самый главный — это рассинхронизация между физическим расположением Controller/Action и правилами доступа для них. Второй по важности — не все правила можно вынести в базу данных, поэтому время от времени этот класс придется переписывать.
Но, в целом, такой подход имеет полное право на существование и, насколько я знаю, используется многими, причем необязательно на платформе от Microsoft.
+1
Вот только потому, что этот подход используют многии я через день вижу не просто деревья if, else — я вижу леса этих деревьев, сплетёными корнями и так далее. Кто-то пытается нанимать смотрителей за этими деревьями — создавая юнит-тесты, но это спасает, но не надолго.
В конечном итоге программисты рвут себе волосы на причинном месте, когда слышут от пользователей или тестеров: Мы почему-то не можем получить доступ к фотографиям. Или: У вас отображается 10 фотографий, а у меня только 5 хотя я супер-администратор.
Я соглашусь с вами только тогда, когда вы покажите мне хотя бы один программый продук где есть права доступа «Всем пользователям которые содержат в своём имени букву Ы в середине слова».
В конечном итоге программисты рвут себе волосы на причинном месте, когда слышут от пользователей или тестеров: Мы почему-то не можем получить доступ к фотографиям. Или: У вас отображается 10 фотографий, а у меня только 5 хотя я супер-администратор.
Я соглашусь с вами только тогда, когда вы покажите мне хотя бы один программый продук где есть права доступа «Всем пользователям которые содержат в своём имени букву Ы в середине слова».
0
О ещё придумала: представте что вашим ПО захотят пользоваться две организации. Но с условием, что ваше ПО будет интегрировано в их систему с уже существующими политиками безопасности.
Не будите же вы переписывать свой код под каждую организацию? А если их будет 10 тыс?
Вообщем вам тоже нужно подтянуть мат.часть :)
Не будите же вы переписывать свой код под каждую организацию? А если их будет 10 тыс?
Вообщем вам тоже нужно подтянуть мат.часть :)
0
Я и не претендую на роль специалиста в этой области, а всего лишь не согласен с постановкой «рановато вам еще статьи писать». Тема статьи — «динамическая проверка», содержание статьи — «динамическая проверка». Кому-то это может в итоге пригодиться в особо сложных ситуациях.
Ну, а то, что это может оказаться не лучшим решением (в большинстве случаев), я с вами полностью согласен.
Пример про интеграцию с существующими политиками безопасности я немного не понял. В любом же случае придется что-то делать? Поясните, пожалуйста.
Ну, а то, что это может оказаться не лучшим решением (в большинстве случаев), я с вами полностью согласен.
Пример про интеграцию с существующими политиками безопасности я немного не понял. В любом же случае придется что-то делать? Поясните, пожалуйста.
0
Я знаю, что такое ACL и роли (работал системным администратором и настройкой прав занимался часто), но стандартный AuthorizeAttribute принимает только константные строки, а что если нужно будет создать новую роль, в которой права отличаются от сущесвующих, и присвоением нескольких существующих ролей не получить нужных прав? Пришлось бы добавлять в код и перекомпилировать.
Приведу пример. Операционная система. Когда нужно создать новую роль, я же не лезу в код ОС, а создаю новую роль и динамически назначаю права доступа этой роли.
Приведу пример. Операционная система. Когда нужно создать новую роль, я же не лезу в код ОС, а создаю новую роль и динамически назначаю права доступа этой роли.
0
>> но стандартный AuthorizeAttribute принимает только константные строки
если чуть расширить реализацию стандартного FilterAttrubuteFilterProvider то в фильтру можно отдать любой тип, а не только переменные уровня компиляции. этот тип вполне может быть контектом доступа к данным, циклом жизни которого управляет кто-то другой, например контейнер.
если чуть расширить реализацию стандартного FilterAttrubuteFilterProvider то в фильтру можно отдать любой тип, а не только переменные уровня компиляции. этот тип вполне может быть контектом доступа к данным, циклом жизни которого управляет кто-то другой, например контейнер.
0
У операционной системы есть уже набор прав которые применяются к разного рода дескрипторам.
После установки операционной системы пользователям SYSTEM, NETWORK SERVICE, LOCAL SERVICE, etc выдаются права доступа.
Грубо говоря, в OS есть некий набор прав и выше упомянутым пользователям раздаются списки доступа, что-то типа 101010101010. А дальше, когда вы создаёте группу, то вы в неё засовываете пользователей, но это не есть _новая_ роль — это всего лишь группа пользователей, у которой можно проверить права.
Для решения конфликтов «Группе запретить, а пользователям входящим в неё разрешить» используется правило «Чем меньше — тем лучше», таким образом запрет имеет больший приоритет над разрешить.
А вот создать НОВУЮ роль, в OS семейства Windows NT — не возможно, т.к. их там вообще нет.
Но, создавать объекты требующие права доступа — это всегда пожалуйста.
Но, вернёмся к «динамическому» распределению прав доступа в вашем примере и будем рассматривать его в стравнении с ОС.
У вас есть набор ресурсов — это actions of controllers (не знаю, как написать). И они просто так не появляются и не исчезают, точно так же как и в ОС не появляется новых, а только те, о которых она, ОС, знает: диски, сетевой стек, рабочий стол, и прочии. Только они не всегда доступны, но они есть и нового «Рога и копыта» ресурса там не появится, а если и появится, то это будет один из ранее известных типов: диск, рабочий стол и так далее.
Теперь у вас есть права Reader/Writer точно так же и у ОС есть Read/Write/Delete/Rename и ещё очень много других.
Таким образом, мы имеем следующее:
Ресурсы «HomeController.Index», «HomeController.About» и так далее и операции Read/Write
Вы не явно создали группу autheticated users & anonymous users и попытались разграничить доступ к ресурсам.
Операционная система имеет такие группы «из коробки» и у этих групп пользователей есть т.н well-known ids (посмотрите в Wiki — там есть).
Операционная система каждому «ресурсу» присваивает во время инсталяции (ну или где-то там в Рендмонде), права доступа для каждого пользователя и дальше программисты позволяют добавлять и изменять эти права.
В итоге: Вам прийдётся каждый раз пересобирать проект, если у вас будут появлятся новые «ресурсы».
И каждый ваш ресурс ДОЛЖЕН иметь уникальный идентификатор в вашей системе безопасности, вне зависимости что вы будите применять RBS или ACLBS.
И как я уже говорила, вы создаёте роли:
HomeController.Index.Reader
HomeController.About.Reader
и так далее, и уже пользователей засовываете в те или иные группы.
А как же решать: Пользователей много, права у них одинаковые. Я что должен их каждого в группу определять?
Ответ: Да, обязаны.
Вы конечно можете изобрести прослойку ввиде групп пользователей, но в конечном итоге вы будите обязаны определить права доступа этого пользователя к тому или иному ресурсу.
Буду надеяться, что мои ответы направят вас на путь истинный.
P.S. Можете почитать на досуге про SAML и Federated Authentication (он же Single Sign-On), Claims
После установки операционной системы пользователям SYSTEM, NETWORK SERVICE, LOCAL SERVICE, etc выдаются права доступа.
Грубо говоря, в OS есть некий набор прав и выше упомянутым пользователям раздаются списки доступа, что-то типа 101010101010. А дальше, когда вы создаёте группу, то вы в неё засовываете пользователей, но это не есть _новая_ роль — это всего лишь группа пользователей, у которой можно проверить права.
Для решения конфликтов «Группе запретить, а пользователям входящим в неё разрешить» используется правило «Чем меньше — тем лучше», таким образом запрет имеет больший приоритет над разрешить.
А вот создать НОВУЮ роль, в OS семейства Windows NT — не возможно, т.к. их там вообще нет.
Но, создавать объекты требующие права доступа — это всегда пожалуйста.
Но, вернёмся к «динамическому» распределению прав доступа в вашем примере и будем рассматривать его в стравнении с ОС.
У вас есть набор ресурсов — это actions of controllers (не знаю, как написать). И они просто так не появляются и не исчезают, точно так же как и в ОС не появляется новых, а только те, о которых она, ОС, знает: диски, сетевой стек, рабочий стол, и прочии. Только они не всегда доступны, но они есть и нового «Рога и копыта» ресурса там не появится, а если и появится, то это будет один из ранее известных типов: диск, рабочий стол и так далее.
Теперь у вас есть права Reader/Writer точно так же и у ОС есть Read/Write/Delete/Rename и ещё очень много других.
Таким образом, мы имеем следующее:
Ресурсы «HomeController.Index», «HomeController.About» и так далее и операции Read/Write
Вы не явно создали группу autheticated users & anonymous users и попытались разграничить доступ к ресурсам.
Операционная система имеет такие группы «из коробки» и у этих групп пользователей есть т.н well-known ids (посмотрите в Wiki — там есть).
Операционная система каждому «ресурсу» присваивает во время инсталяции (ну или где-то там в Рендмонде), права доступа для каждого пользователя и дальше программисты позволяют добавлять и изменять эти права.
В итоге: Вам прийдётся каждый раз пересобирать проект, если у вас будут появлятся новые «ресурсы».
И каждый ваш ресурс ДОЛЖЕН иметь уникальный идентификатор в вашей системе безопасности, вне зависимости что вы будите применять RBS или ACLBS.
И как я уже говорила, вы создаёте роли:
HomeController.Index.Reader
HomeController.About.Reader
и так далее, и уже пользователей засовываете в те или иные группы.
А как же решать: Пользователей много, права у них одинаковые. Я что должен их каждого в группу определять?
Ответ: Да, обязаны.
Вы конечно можете изобрести прослойку ввиде групп пользователей, но в конечном итоге вы будите обязаны определить права доступа этого пользователя к тому или иному ресурсу.
Буду надеяться, что мои ответы направят вас на путь истинный.
P.S. Можете почитать на досуге про SAML и Federated Authentication (он же Single Sign-On), Claims
0
Всё ок, только не надо забывать про использование area в asp.net mvc. Т.е. я могу создать два одинаковых контроллера с двумя одинаковыми экшнами, но в разных area. Например: Admin/Home/Index, Default/Home/Index, где первый для админа, а второй для всех.
Так вот тут
Ну и проверять соответственно.
Так вот тут
public class DynamicAuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
...
string area = filterContext.RouteData.DataTokens["area"] as string;
....
}
Ну и проверять соответственно.
0
Взгляните на реализацию прав доступ в Orchard или nopCommerce
0
На самом деле ваш пример ничем не отличается от подхода, предложенного Angelina_Joulie, если добавить роли вида ContollerName_ActionName и указать, что только эта роль имеет досуп к соответствующему экшену. Ну а стандартный role provider позволяет назначить роли на лету. Да, ролей будет много, но в вашем подходе информации кто к чему имеет доступ уж точно будет не меньше. Повторюсь, перекомпиляция не требуется.
На мой взгляд реализовывать IAuthorizationFilter стоит тогда, когда авторизации зависит динамических параметров, от окружения. Например, пользователь может не иметь доступ к экшену с 10 вечера до 7 утра (ну чем не родительский контроль), или часть информации не доступна в зависимости от страны и т.д.
На мой взгляд реализовывать IAuthorizationFilter стоит тогда, когда авторизации зависит динамических параметров, от окружения. Например, пользователь может не иметь доступ к экшену с 10 вечера до 7 утра (ну чем не родительский контроль), или часть информации не доступна в зависимости от страны и т.д.
0
Полностью поддерживаю вариант с ограниченым временем владения прав к ресурсу.
Тогда, да, динамически нужно проверять.
Но, если разобраться в деталях, то динамикой тут и не пахнет — просто появляется новый аттрибут «Время».
Если «из коробки» мы имеем только IPrincipal.IsInRole(string), что ограничивает нас в том, что абстракция роль — это только строка, но ведь могла бы роль быть представленна как объект Имя и Время. А дальше, дело техники — во время проверки проверять не только наличие пользователя в группе, но и корректность аттрибуте «Время».
Вы сразу же можете броситься изобретать велосипед, но хочу вас огорчить — всё уже давно придумали. И даже написали спецификацию. Называется это всё Security Assertion Markup Language (спросите Wiki она вам подскажет подробнее).
И основная концепция — это выдача т.н. SAML токенов.
Кстати, Windows тоже этим же и занимается — выдаёт при аутентификации SID (правда их там много разных), но выдаёт токен «уже с правами».
Ну как-то так)))
Тогда, да, динамически нужно проверять.
Но, если разобраться в деталях, то динамикой тут и не пахнет — просто появляется новый аттрибут «Время».
Если «из коробки» мы имеем только IPrincipal.IsInRole(string), что ограничивает нас в том, что абстракция роль — это только строка, но ведь могла бы роль быть представленна как объект Имя и Время. А дальше, дело техники — во время проверки проверять не только наличие пользователя в группе, но и корректность аттрибуте «Время».
Вы сразу же можете броситься изобретать велосипед, но хочу вас огорчить — всё уже давно придумали. И даже написали спецификацию. Называется это всё Security Assertion Markup Language (спросите Wiki она вам подскажет подробнее).
И основная концепция — это выдача т.н. SAML токенов.
Кстати, Windows тоже этим же и занимается — выдаёт при аутентификации SID (правда их там много разных), но выдаёт токен «уже с правами».
Ну как-то так)))
0
Так я и сказал, что это только пример, как будет работать авторизация у вас, зависит только от вас. Просто статьей хотелось сказать, что есть возможность переопределить стандартный механизм. Есть люди, которые ASP.NET MVC увидели недавно, поэтому для них всё в первой. А в рунете предлагается, в основном, только вариант, предложенный Angelina_Joulie
0
Если говорить о динамике, то смотреть и на параметры экшена. Например, одной группе пользователей разрешим доступ к /Home/Index/12, и запретим к /Home/Index/19, а другой группе наоборот. С возможностью раздачей таких прав без перекомпиляции. Вот это я назову динамическим разграничением.
0
Можно ещё много какую угодно проверку сделать, просто хотелось показать, что переделать стандартную авторизацию не просто, а очень просто и не делать простынку из исходного кода. А все посмотрели на статичного PermissionManager'a и не видят динамической проверки.
0
В вашем примере есть определение имени контроллера, экшена, и имени пользователя. Я к тому, что было бы полезно показать как параметры самого экшена выдёргивать из запроса. Для полноты картины. А уже на этой основе можно делать полностью динамическую проверку.
0
Вы даже и не коснулись механизма проверки — это раз.
Подумайте над cледующими строками:
/>
/>
/>
/>
/>
/>
/>
(взято из глобального web.config'a)
Это и есть механизм аутентификации и авторизации.
Подумайте над cледующими строками:
/>
/>
/>
/>
/>
/>
/>
(взято из глобального web.config'a)
Это и есть механизм аутентификации и авторизации.
0
<httpModules>
<add name="OutputCache" type="System.Web.Caching.OutputCacheModule" />
<add name="Session" type="System.Web.SessionState.SessionStateModule" />
<add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
<add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" />
<add name="RoleManager" type="System.Web.Security.RoleManagerModule" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
<add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" />
<add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" />
<add name="Profile" type="System.Web.Profile.ProfileModule" />
<add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
<add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpModules>
0
Only those users with full accounts are able to leave comments. Log in, please.
Динамическая проверка прав доступа для ASP.NET MVC