ruby-on-rails 使用关键字HTTP_AUTHORIZATION而不是Authorization访问Ruby on Rails中的授权头?

4si2a6ki  于 2022-12-05  发布在  Ruby
关注(0)|答案(2)|浏览(126)

我希望有人能为我澄清一些事情。我使用的是Rails 2.3.5,我可以在控制器操作中访问请求头,如下所示:

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

request.headers是ActionController::Http::Headers的一个示例,它看起来是一个Hash函数,因此我希望header是以我发送的名字为键的,但是如果我发送一个请求,带有一个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']

似乎有一些我不知道的魔法在发生。我完全搞不懂为什么检查'Authorization'键失败,但是呈现request.headers ['Authorization']的值成功了。我也搞不懂'HTTP_AUTHORIZATION'是从哪里来的,因为它 * 不是 * 我和请求一起发送的头的名称。有人知道到底发生了什么吗?

pdsfdshx

pdsfdshx1#

您是正确的-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

因此,当通过[]访问Hash时,需要再次检查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有一些非常好的源代码,这些年来我从中学到了很多。

flseospp

flseospp2#

根据通用网关接口RFC:
如果使用的协议是HTTP,则名称以"HTTP_"开头的元变量包含从客户机请求头字段中读取的值。HTTP头字段名称转换为大写,所有"-"替换为"_",并在前面加上"HTTP_"以给予元变量名称。

相关问题