Статьи

Авторизация вашего Rails-приложения с помощью Authority

Представьте, что вы пишете приложение Rails для организации конференций. Как только вы узнаете, что может делать приложение, вы должны начать решать, кто что может делать. Кому разрешено:

  • Решите, кто будет выступать на конференции?
  • Изменить расписание докладчика?
  • Загрузить слайды презентации?
  • Прокомментировать эти слайды?
  • Создавать плейлисты музыки?
  • Составьте личный график, какие разговоры посмотреть?

Все эти вопросы касаются авторизации: «что должен делать этот пользователь?» Очевидно, что важно правильно понять эту логику: она должна быть правильной и последовательной. И было бы неплохо, если бы эта логика была сгруппирована, а не разбросана по всему приложению.

Я только что выпустил драгоценный камень, чтобы решить эту проблему чисто. Это называется Authority (см. Github и Rubygems ).

Защита ваших моделей

Прежде чем я покажу вам, как работает Authority, давайте поговорим о некоторых общих идеях.

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

В других случаях вопрос более нюансирован: участники могут редактировать свое личное расписание, но не чье-либо другое. Вы можете думать об этом как о правиле «уровня экземпляра»: чтобы узнать, может ли участник конференции редактировать расписание, вам нужно посмотреть на этот экземпляр расписания и посмотреть, кому он принадлежит.

Используя Authority, вы будете использовать методы класса, такие как def self.updatable_by?(user)def deletable_by?(user)

Но где эти методы должны быть написаны?

Сохраняя ваши разрешения СУХОЙ

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

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

Власть выполняет это, позволяя модели делегировать любые вопросы авторизации указанному классу Авторизатора. Модели с одинаковыми правилами могут указывать на одного и того же Авторизатора.

Пример

Чтобы взять простой пример из README, представьте, что у вас двоих есть категории ресурсов в вашем приложении: некоторые для обычных пользователей, а некоторые для администраторов. Используя Authority, у вас будет два класса авторизатора. Вы можете называть их BasicAuthorizerAdminAuthorizer

Вы можете сгруппировать свои модели следующим образом:

BasicAuthorizer AdminAuthorizer
+ +
+-+ +——+
+ + +
Comment Article Edition

view raw
gistfile1.txt
hosted with ❤ by GitHub

В этом примере правила авторизации модели CommentBasicAuthorizerArticleEditionAdminAuthorizer Вы должны вызвать self.authorizer_name =

AdminAuthorizer

class AdminAuthorizer < Authority::Authorizer
def self.creatable_by?(user)
user.is_admin?
end
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Каждый раз, когда пользователь пытается создать ArticleEdition Если пользователь не является администратором, он вернет false и действие будет отклонено.

Любой метод, который не определен в авторизаторе, будет унаследован от Authority::Authorizerdefault_strategy Встроенная стратегия по умолчанию просто возвращает false. Это подход из белого списка: любые действия, которые вы явно не разрешаете, будут запрещены. Но вы можете предоставить свою собственную стратегию по умолчанию, чтобы сделать что-то более нюансированное.

Таким образом, полная цепочка поиска выглядит следующим образом:

default_strategy
+
+———+——-+
+ +
BasicAuthorizer AdminAuthorizer
+ +
+-+ +——+
+ + +
Comment Article Edition

view raw
gistfile1.txt
hosted with ❤ by GitHub

Стандартные классы и методы Ruby

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

Кроме того, методы авторизатора — это просто простые методы Ruby: нет нового синтаксиса для изучения. Власть не делает никаких предположений о том, какая логика вам понадобится. Вы можете обратиться к базе данных, файлу или веб-службе для принятия решений; если вы используете базу данных, вы можете использовать любой ORM, который вам нравится. Вся логика зависит от вас; Авторитет просто помогает вам держать это организованным.

Синтаксический сахар для пользователей

До сих пор мы видели наши методы авторизации в пассивном голосе: этот ресурс создается этим пользователем? Но приятно иметь возможность говорить то же самое активным голосом: может ли этот пользователь создать этот ресурс?

Как и несколько других популярных жетонов авторизации, Authority предоставляет вам этот синтаксический сахар. current_user.can_edit?(@article)@article.editable_by?(current_user)AdminAuthorizer

Так как can_edit? и аналогичные методы определены для объекта пользователя, вы можете использовать их везде, где доступен объект. Распространенным случаем будет показывать ссылки только тем пользователям, которые должны их видеть:

link_to new_article_path if current_user.can_create?(Article)

view raw
gistfile1.rb
hosted with ❤ by GitHub

Маленькая магия для контроллеров

Если вы используете метод, показанный выше, чтобы скрыть ссылки от неавторизованных пользователей, большинство людей не будут пытаться делать то, что им не следует делать. Но что если кто-то вручную введет URL-адрес, чтобы отредактировать запрещенный для них ресурс?

В этот момент ваш контроллер должен вмешаться. Authority предоставляет вам несколько методов для этого: authorize_actions_for(ModelName)authorize_action_for(@model_instance)

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

Проверьте это

Вы можете получить более подробную информацию обо всем, что обсуждается здесь, посмотрев README на Github . Я также рекомендую вам прочитать исходный код; Авторитет не большая жемчужина, и источник хорошо прокомментирован. Вы можете чему-то научиться, и, конечно же, чтение кода — это первый шаг к тому, чтобы внести свой вклад.

Счастливого взлома!