Получение текущего запроса в рельсах из файла в lib/

StackOverflow https://stackoverflow.com/questions/1002200

  •  05-07-2019
  •  | 
  •  

Вопрос

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

lib/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], как в контроллере, потому что параметры не определены;аналогично request.parameters[:foo] тоже не будет работать.Мои поиски выявили:

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

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

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

Решение

В типичном приложении 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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top