Заголовок авторизации в Ruby on Rails доступен с ключом HTTP_AUTHORIZATION вместо Авторизации? - PullRequest
27 голосов
/ 22 февраля 2010

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

def index
  if request.headers['...'] == '...'
    ...
  end
end

Или что-то подобное. request.headers является экземпляром ActionController :: Http :: Headers , который выглядит как Hash. Поэтому я ожидаю, что заголовки указываются на имени, которое я посылаю. Однако если я отправлю запрос с заголовком Authorization , например:

curl -H 'Authorization: OAuth realm="MyRealm",...' http://app/path

Следующий код в действии возвращает false:

if request.headers.include?('Authorization') ... 

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

render :text => request.headers['Authorization']

Следующая проверка возвращает true, что довольно интересно:

if request.headers.include?('HTTP_AUTHORIZATION') ... 

И аналогично, следующее повторяет значение, которое я отправляю в заголовке:

render :text => request.headers['HTTP_AUTHORIZATION']

Кажется, что происходит какое-то волшебство, о котором я не знаю. Я полностью сбит с толку относительно того, почему проверка ключа «Авторизация» завершается неудачно, но рендеринг значения request.headers ['Authorization'] завершается успешно. Я также не совсем понимаю, откуда исходит HTTP_AUTHORIZATION, поскольку это , а не имя заголовка, который я отправляю вместе с запросом. Кто-нибудь знает, что именно происходит?

Ответы [ 2 ]

30 голосов
/ 26 февраля 2010

Вы правы - метод headers для ActionController::Request возвращает экземпляр ActionController::Http::Headers, который наследуется от Hash. Если мы взломаем источник, мы увидим это:

class Headers < ::Hash
  extend ActiveSupport::Memoizable

  def initialize(*args)
     if args.size == 1 && args[0].is_a?(Hash)
       super()
       update(args[0])
     else
       super
     end
   end

  def [](header_name)
    if include?(header_name)
      super
    else
      super(env_name(header_name))
    end
  end

  private
    # Converts a HTTP header name to an environment variable name.
    def env_name(header_name)
      "HTTP_#{header_name.upcase.gsub(/-/, '_')}"
    end
    memoize :env_name
end

Таким образом, при обращении к хэшу через [], есть вторая проверка, чтобы увидеть, существует ли значение из env_name (которое просто преобразует ключ в ключ и добавляет HTTP_).

Вот почему вы не можете получить истинное значение из request.headers.include?('Authorization') - include? не переопределяется в подклассе для проверки как обычной, так и расширенной версии заголовка. Я полагаю, что вы могли бы последовать этому примеру и реализовать его самостоятельно так:

module ActionController
  module Http
    class Headers < ::Hash
      def include?(header_name)
        self[header_name].present?
      end
    end
  end
end

Бросьте это в lib/extensions/action_controller.rb или что-то еще, потребуйте его в environment.rb, если это необходимо, и вам будет хорошо идти. Я бы порекомендовал просто изменить код вашего контроллера, чтобы использовать [] и present? для проверки:)

Причина в том, что заголовки имеют префикс с префиксом HTTP_, я полагаю, проистекает из Rack, промежуточного программного обеспечения Rails HTTP. Вероятно, он делает это, чтобы оставаться беспристрастным по отношению к делу, дополнительно добавляя HTTP_, чтобы избежать конфликтов с другими входящими в окружение материалами, не являющимися заголовками.

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

6 голосов
/ 25 ноября 2014

Согласно Общий интерфейс шлюза RFC :

Метапеременные с именами, начинающимися с "HTTP_", содержат значения читать из полей заголовка запроса клиента, если используется протокол HTTP. Имя поля заголовка HTTP преобразуется в верхний регистр, имеет все вхождения "-" заменены на "_" и имеют префикс "HTTP_" дать имя мета-переменной.

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