使用密钥HTTP_AUTHORIZATION而不是Authorization访问Ruby on Rails中的授权头?

时间:2010-02-22 15:24:51

标签: ruby-on-rails http

我希望有人可以为我清理一些东西。我正在使用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'来自哪里,因为我正在发送请求的标头的名称。有谁知道究竟发生了什么?

2 个答案:

答案 0 :(得分:29)

您是对的 - 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有一些很好的资源,我多年来从中学到了很多东西。< / p>

答案 1 :(得分:5)

根据The Common Gateway Interface RFC

  

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