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

Pau*_*man 28 ruby-on-rails http

我希望有人可以为我清理一些东西.我正在使用Rails 2.3.5,我可以在控制器动作中访问请求标头,如下所示:

def index
  if request.headers['...'] == '...'
    ...
  end
end
Run Code Online (Sandbox Code Playgroud)

或类似的东西.request.headers是ActionController :: Http :: Headers的一个实例,它看起来像是一个Hash.因此,我希望标题符合我发送的名称.但是,如果我发送请求,请使用Authorization标头,如下所示:

curl -H 'Authorization: OAuth realm="MyRealm",...' http://app/path
Run Code Online (Sandbox Code Playgroud)

操作中的以下代码返回false:

if request.headers.include?('Authorization') ... 
Run Code Online (Sandbox Code Playgroud)

以下回应我在标题中发送的值:

render :text => request.headers['Authorization']
Run Code Online (Sandbox Code Playgroud)

以下检查返回true,有趣的是:

if request.headers.include?('HTTP_AUTHORIZATION') ... 
Run Code Online (Sandbox Code Playgroud)

同样,以下内容回显了我在标头中发送的值:

render :text => request.headers['HTTP_AUTHORIZATION']
Run Code Online (Sandbox Code Playgroud)

似乎有一些我不知道的神奇事件.我完全混淆为什么检查密钥'授权'失败,但渲染request.headers ['Authorization']的值成功.我也很困惑'HTTP_AUTHORIZATION'来自何处,因为这不是我随请求发送的标头的名称.有谁知道究竟发生了什么?

Bre*_*ham 30

你是正确的-该headers方法ActionController::Request返回的实例ActionController::Http::Headers,这是从哈希继承.如果我们破解源代码,我们会看到:

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
Run Code Online (Sandbox Code Playgroud)

因此,当访问Hash via时[],会进行第二次检查以查看是否存在来自env_name(仅提升密钥和prepends 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
Run Code Online (Sandbox Code Playgroud)

把它扔进lib/extensions/action_controller.rb或什么东西,environment.rb必要时需要它,你应该好好去.我建议只修改你要使用的控制器代码[]present?进行检查,但:)

我认为,标题是upcased和前缀的原因HTTP_源于Rack,Rails的HTTP中间件.这可能是为了保持关于案例的公正,另外HTTP_还要避免与其他非标题环境内容冲突.

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


war*_*iuc 6

根据通用网关接口RFC:

"HTTP_"如果使用的协议是HTTP,则名称以包含值的元变量从客户端请求头字段读取.HTTP标头字段名称转换为大写,所有出现的"-"替换为,"_"并且已经"HTTP_"预先赋予元变量名称.