【问题标题】:Authorization header in Ruby on Rails accessed with key HTTP_AUTHORIZATION instead of Authorization?使用密钥 HTTP_AUTHORIZATION 而不是授权访问 Ruby on Rails 中的授权标头?
【发布时间】:2010-02-22 15:24:50
【问题描述】:

我希望有人可以为我解决问题。我使用的是 Rails 2.3.5,我可以像这样在控制器操作中访问请求标头:

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

或类似的东西。 request.headers 是ActionController::Http::Headers 的一个实例,它似乎是一个哈希。因此,我希望标题以我发送的名称为关键字。但是,如果我发送带有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”的来源感到困惑,因为这 不是 我与请求一起发送的标头的名称。有谁知道具体是怎么回事?

【问题讨论】:

  • 我花了一个小时才弄清楚这一点。我认为这很令人困惑:至少他们应该更好地记录这种行为。

标签: ruby-on-rails http


【解决方案1】:

你是对的 - ActionController::Requestheaders 方法返回一个 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_ 为前缀,我相信,源于Rails 的HTTP 中间件Rack。这样做可能是为了保持对大小写的公正,另外在前面加上 HTTP_ 以避免与其他非标头环境内容发生冲突。

所以,是的,有点神奇,但在查看源代码后并不难理解,我总是推荐 :) Rails 有一些非常好的源代码,这些年来我从中学到了很多。

【讨论】:

  • 谢谢布伦特!我会避免打鸭子,只用礼物?就像你建议的那样。仍然对原因感到好奇,但你给了我一个很好的起点。
  • 非常感谢布伦特! Rails 自动大写并附加标头与 'HTTP_' 非常棘手和奇怪 :(
【解决方案2】:

根据The Common Gateway Interface RFC

名称以"HTTP_" 开头的元变量包含值 从客户端请求头字段中读取,如果使用的协议是 HTTP。 HTTP 头字段名称转换为大写,有 所有出现的"-" 都替换为"_" 并在前面加上"HTTP_" 给出元变量名称。

【讨论】:

    猜你喜欢
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-03
    • 2012-10-23
    • 2016-09-05
    • 1970-01-01
    • 2017-02-04
    相关资源
    最近更新 更多