Authorization header in Ruby on Rails accessed with key HTTP_AUTHORIZATION instead of Authorization?

后端 未结 2 1511
执笔经年
执笔经年 2020-12-13 13:50

I\'m hoping someone can clear something up for me. I\'m using Rails 2.3.5, and I can access request headers in a controller action like this:

def index
  if          


        
相关标签:
2条回答
  • 2020-12-13 14:15

    You are correct - the headers method of ActionController::Request returns an instance of ActionController::Http::Headers, which is inherits from Hash. If we crack open the source, we see this:

    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
    

    So when accessing the Hash via [], there's a second check to see if value from env_name (which just upcases the key and prepends HTTP_) exists.

    This is why you can't get a true value from request.headers.include?('Authorization') -- include? is not overridden in the subclass to check for both the normal and upcased version of the header. I imagine you could follow suit and implement it yourself like this:

    module ActionController
      module Http
        class Headers < ::Hash
          def include?(header_name)
            self[header_name].present?
          end
        end
      end
    end
    

    Throw that into lib/extensions/action_controller.rb or something, require it in environment.rb if necessary, and you should be good to go. I'd recommend just modifying your controller code to use [] and present? to do the check, though :)

    The reason that the headers are upcased and prefixed with HTTP_, I believe, stems from Rack, Rails' HTTP middleware. It probably does this to remain impartial about case, additionally prepending HTTP_ to avoid conflicts with other non-header environment stuff that comes in.

    So, yes, a bit magical, but not too hard to understand after glancing at the source, which I'd always recommend :) Rails has some very nice source that I've learned a lot from over the years.

    0 讨论(0)
  • 2020-12-13 14:18

    According to The Common Gateway Interface RFC:

    Meta-variables with names beginning with "HTTP_" contain values read from the client request header fields, if the protocol used is HTTP. The HTTP header field name is converted to upper case, has all occurrences of "-" replaced with "_" and has "HTTP_" prepended to give the meta-variable name.

    0 讨论(0)
提交回复
热议问题