Подтвердить что ты не робот

Авторизация авторизации

Я создаю сайт на основе сообщества в Rails для членов реальной организации. Я стараюсь придерживаться лучших практик дизайна RESTful, и большинство из них более или менее по-книжной. Проблема, заключающаяся в том, что мой мозг работает в опрятных кругах RESTful, это вопрос авторизации. Аутентификация - это легкая, долго разрешенная проблема с широко принятыми решениями RESTful, но авторизация RESTful, по-видимому, немного черная. Я пытаюсь найти подход, который обеспечит наиболее общую и гибкую структуру для контроля доступа к ресурсам, будучи как можно более простым, и все это будет соответствовать архитектуре RESTful. (Также, пони.)

Вопросы:

  • Мне нужно контролировать доступ к различным ресурсам, таким как пользователи, страницы, сообщения и т.д.
  • Авторизация для данного ресурса должна быть более тонкой, чем простой CRUD.
  • Я хочу позволить себе и другим редактировать правила авторизации из приложения.
  • Правила авторизации должны зависеть от предикатов, таких как (концептуально) Владелец (Пользователь, Ресурс) или Заблокировано (Тема)

Рассмотрение (2) - это тот, который касается меня больше всего. Кажется, существует несоответствие импеданса между моей концепцией разрешений и концепцией RESTful действий. Например, возьмите сообщения (как на доске объявлений). REST определяет существование четырех операций на ресурсе Post: создание, чтение, обновление и удаление. Легко сказать, что пользователь должен иметь возможность обновлять свои собственные сообщения, но только определенным пользователям (или ролям или группам) должно быть разрешено блокировать их. Традиционный способ представления блокировки находится в состоянии сообщения, но это приводит к запаху, который Пользователь в тех же условиях может или не сможет обновить сообщение в зависимости от (полностью допустимых) значений, которые он поставляет. Мне кажется ясным, что есть действительно два разных действия, чтобы изменить состояние Почты, и обучать их просто замаскировать нарушение принципов RESTful.

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

Разве не разложено другое слово для гниения?

Это можно преодолеть, разложив сообщение: блокировка - это субресурс определенного сообщения, а для создания или уничтожения один может иметь отдельные разрешения. У этого решения есть кольцо REST, но оно приносит с собой как теоретические, так и практические трудности. Если я определяю блокировки, то как насчет других атрибутов? Предположим, я решил, в припадке каприза, разрешить только члену Администратора изменять заголовок сообщения? Простое изменение авторизации потребует реструктуризации базы данных для ее размещения! Это не решение. Чтобы обеспечить такую ​​гибкость в стратегии декомпозиции, требуется, чтобы каждый атрибут был ресурсом. Это немного дилемма. Мое неявное предположение заключалось в том, что ресурс представлен в базе данных в виде таблицы. В этом предположении ресурс для каждого атрибута означает таблицу для каждого атрибута. Ясно, что это нецелесообразно. Однако, чтобы удалить это предположение, возникает несоответствие импеданса между таблицами и ресурсами, что может открыть собственную банку червей. Использовать этот подход потребовало бы гораздо более глубокого рассмотрения, чем я дал. Во-первых, пользователи разумно ожидают, что смогут редактировать сразу несколько атрибутов. Куда идет запрос? К самому маленькому ресурсу, который содержит все атрибуты? Для каждого отдельного ресурса параллельно? К луне?

Некоторые из этих вещей не похожи на других...

Предположим, что я не разлагаю атрибуты. Альтернативой тогда, кажется, является определение набора привилегий для каждого ресурса. На данный момент, однако, однородность REST теряется. Чтобы определить правила доступа к ресурсу, система должна обладать конкретными знаниями об этих ресурсах. Кроме того, теперь невозможно в общих чертах распространять разрешения на ресурсы потомков, даже если дочерний ресурс имеет привилегию с тем же именем, нет никакой врожденной семантической связи между привилегиями. Определение REST-подобного набора стандартных привилегий представляется мне наихудшим из обоих миров, поэтому я придерживаюсь отдельной иерархии разрешений для каждого типа ресурсов.

Хорошо, мы сделали нос. И шляпа. Но это ресурс!

Одно из предположений, которое я видел, смягчает некоторые из недостатков вышеупомянутого подхода, заключается в определении разрешений, таких как создание/удаление ресурсов и чтение/запись атрибутов. Эта система является компромиссом между атрибутами-ресурсами и привилегиями для каждого ресурса: по-прежнему остается только CRUD, но для целей авторизации чтение и обновление относятся к атрибутам, которые можно рассматривать как псевдоресурсы. Это обеспечивает многие практические преимущества подхода "атрибуты-ресурсы", хотя концептуальная целостность в определенной степени скомпрометирована. Разрешения могут распространяться от ресурса к ресурсу и от ресурса до псевдо-ресурса, но никогда от псевдо-ресурса. Я не полностью изучил последствия этой стратегии, но кажется, что это может быть многообещающим. Мне приходит в голову, что такая система лучше всего будет функционировать как неотъемлемая часть Модели. Например, в Rails это может быть модификация ActiveRecord. Для меня это выглядит довольно радикально, но авторизация является такой фундаментальной сквозной проблемой, что это может быть оправдано.

О, и не забывайте о пони

Все это игнорирует проблему предикативных разрешений. Очевидно, что Пользователь должен иметь возможность редактировать свои собственные сообщения, но никого другого. В равной степени очевидно, что в таблице администраторских разрешений не должно быть отдельных записей для каждого пользователя. Это вряд ли является необычным требованием - трюк делает его общим. Я думаю, что вся необходимая функциональность могла бы быть получена, если бы предикативы правил были предикатами, так что возможность применения правила могла быть решена быстро и немедленно. Правило "allow User write Post where Author(User, Post)" переведет "for all User, Post such that Author(User, Post), allow User write Post" и "deny all write Post where Locked(Post)" на "for all Post such that Locked(Post), deny all write Post". (Было бы замечательно, если бы все такие предикаты могли быть выражены в терминах одного Пользователя и одного Ресурса.) Концептуально результирующие "окончательные" правила были бы не предикативными. Это ставит вопрос о том, как реализовать такую ​​систему. Предикаты должны быть членами классов Model, но я не уверен, как можно грамотно относиться к ним в контексте правил. Чтобы сделать это безопасно, потребовалось бы какое-то отражение. Здесь снова возникает ощущение, что для этого потребуется модернизация реализации модели.

Как вы повторяете это снова?

Последний вопрос - как лучше всего представить эти правила авторизации в качестве данных. Таблица базы данных может сделать трюк с столбцами enum для allow/deny и C/R/U/D (или, возможно, CRUD-бит? Или, возможно, {C, R, U, D} × {allow, deny, inherit}?), и столбец ресурсов с контуром. Возможно, в качестве удобства, "наследовать" бит. Я в недоумении до предикатов. Отдельная таблица? Конечно, много кеширования, чтобы помешать ему быть слишком нехорошим.


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

4b9b3361

Ответ 1

Извините, у меня нет времени, чтобы сделать этот вопрос справедливым, но приятно видеть некоторые хорошо продуманные вопросы о SO. Вот несколько комментариев:

Не попадайте в ловушку отображения HTTP-глаголов в CRUD. Да GET и DELETE карты довольно чисто, но PUT может создавать и обновлять (но только полную замену), а POST - это подстановочный глагол. POST действительно обрабатывает все, что не вписывается в GET, PUT и УДАЛИТЬ.

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

POST /LockedPosts?url=/Post/2010

Подресурс также является действительным подходом к управлению текущим состоянием ресурса. Я бы не счел необходимым относиться к атрибутам "состояние" ресурса и его атрибутам "данных" согласованным образом.

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

Мы регулярно видим, как Rails, ASP.NET MVC и пользователи WCF Rest публикуют здесь вопросы о StackOverflow о том, как некоторые вещи находятся в пределах ограничений REST. Проблема часто не является ограничением REST, а ограничением рамки в ее поддержке приложений RESTful. Я думаю, что очень важно сначала найти решение RESTful для проблемы, а затем посмотреть, можно ли отобразить его обратно в вашу структуру выбора.

Что касается создания модели разрешений, которая существует на более мелком зерне, чем сам ресурс. Помните, что одним из ключевых ограничений REST является гипермедиа. Hypermedia может использоваться не только для поиска связанных объектов, но и для представления допустимых/разрешенных переходов состояний. Если вы возвращаете представление, чем содержит встроенные ссылки, условно на основе разрешений, то вы можете контролировать, какие действия могут быть выполнены кем. то есть если пользователь имеет разрешения на разблокировку POST 342, то вы можете вернуть следующую ссылку, встроенную в представление:

<Link href="/UnlockedPosts?url=/Post/342" method="POST"/>

Если у них нет этого разрешения, не возвращайте ссылку.

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

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

Ответ 2

Недавно я обнаружил решение для проверки подлинности, которое, как представляется, касается большинства моих проблем. Если вы любите этот вопрос, это может вас заинтересовать:

https://github.com/stffn/declarative_authorization

Ответ 3

Как отметил Даррел - REST - это не CRUD. Если вы обнаружите, что ваши идентифицированные ресурсы слишком грубы, что единый интерфейс не обеспечивает достаточного контроля, тогда разделите свой ресурс на под-ресурсы и используйте исходный ресурс как "коллекцию" гиперссылок на его компоненты.