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

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

你是对的 – ActionController::Requestheaders方法返回一个ActionController::Http::Headers的实例,它inheritance自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 

因此,当通过[]访问Hash时,会进行第二次检查,以查看是否存在来自env_name值(它只是提升了密钥并预先设置了HTTP_ )。

这就是为什么你无法从request.headers.include?('Authorization')获得真正的价值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? 做检查,但:)

我相信,标题是upxased并以HTTP_为前缀的原因源于Rack,Rails的HTTP中间件。 这可能是为了保持对案件的公正,另外在HTTP_之前预先设置,以避免与其他非标题环境内容冲突。

所以,是的,有点神奇,但在浏览源代码后并不难理解,我总是建议这样做:Rails有一些非常好的来源,我多年来从中学到了很多东西。

根据通用网关接口RFC :

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