Получение текущего запроса в rails из файла в lib / - PullRequest
1 голос
/ 16 июня 2009

Я поместил весь свой код аутентификации пользователя в одном месте, а именно в lib / auth.rb. Это выглядит так:

Библиотека / auth.rb

module Admin

  def do_i_have_permission_to?(permission)
    # Code to check all of this goes here
  end

end

Я включаю этот модуль как часть помощника приложения, поэтому эти функции доступны во всех представлениях:

application_helper.rb

require 'auth'
module ApplicationHelper
  include Admin
  # other stuff here
end

И я также включаю его как часть контроллера приложения, чтобы контроллеры также могли вызывать функции:

application.rb

require 'auth'
class ApplicationController < ActionController::Base
  include Admin
end

Пока все хорошо.

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

Это означает, что, если администратор хочет что-то сделать, этот администратор должен сначала отключить всех, что раздражает. Но мы хотим получить одобрение администратора на все, что делает администратор. Поэтому мне было предложено сделать так, чтобы администратор мог предоставить комбинацию имени пользователя и пароля на любой странице, к которой у них обычно не было бы доступа (например, на странице «Изменить пользователя» были бы эти дополнительные поля ввода), а процедуры аутентификации проверьте это. Это значит

Admin::do_i_have_permission_to?(permission)

необходимо получить при текущих параметрах запроса. Я не могу просто использовать params [: foo], как в контроллере, потому что params не определен; аналогично request.parameters [: foo] также не будет работать. Мой поиск выявил:

  • Текущие параметры поиска находятся в текущем запросе,
  • Текущий запрос находится в текущем контроллере,
  • Текущий контроллер находится в текущем диспетчере, а
  • Я не уверен, что текущий диспетчер хранится где-либо.

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

  • Просто переместите все функции, находящиеся в настоящее время в auth.rb, в ApplicationHelper, где (я думаю) они будут иметь доступ к запросу и тому подобное. Работает, но черт побери из помощника.
  • Переместите все функции куда-нибудь еще, они увидят эти методы (я не знаю, где)
  • Я просто что-то упустил.

1 Ответ

4 голосов
/ 16 июня 2009

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

Кажется довольно необычным создание модуля, который затем включается в ApplicationHelper. Традиционный подход заключается в создании отдельного помощника, который в этом случае, вероятно, будет называться AuthenticationHelper. Затем его можно включить в любые необходимые контроллеры или, если хотите, загрузить в ApplicationController, чтобы сделать его доступным повсеместно.

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

Вспомогательные методы имеют полный доступ к любым переменным экземпляра, объявленным в контексте контроллера, из которого они работают. Точнее, это только переменные экземпляра (@name), а не локальные переменные (name). Вспомогательные методы также выполняются для определенного представления.

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

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

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

Хотя заманчиво накатывать целую кучу таких, как can_edit_user? и can_create_group? они очень быстро выходят из-под контроля. Это более простой дизайн, чтобы положить в ловушку для общего назначения can_perform? или has_authority_to? метод, которому передается операция и все необходимые параметры.

Например, очень грубая реализация:

  class ApplicationController < ActionController::Base
  protected
    def has_authority_to?(operation, conditions = { })
      AuthenticationCheck.send(operation, conditions)
    rescue
      false
    end
  end

  module AuthenticationCheck
    def self.edit_user?(conditions)
      session_user == conditions[:user]
    end
  end

  class UserController
    # ...

    def edit
      @user = User.find(params[:id])

      unless (has_authority_to?(:edit_user, :user => @user))
        render(:partial => 'common/access_denied', :status => :forbidden)
      end
    rescue ActiveRecord::RecordNotFound
      render(:partial => 'users/not_found')
    end
  end

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

Может быть полезен полный пример структуры, такой как система аутентификации пользователя Wristband:

http://github.com/theworkinggroup/wristband/tree/master

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