2010-02-22 38 views
27

Tôi hy vọng ai đó có thể xóa một số thứ cho tôi. Tôi đang sử dụng Rails 2.3.5 và tôi có thể truy cập các tiêu đề yêu cầu trong một hành động điều khiển như sau:Tiêu đề ủy quyền trong Ruby on Rails được truy cập bằng khóa HTTP_AUTHORIZATION thay vì Ủy quyền?

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

Hoặc tương tự. request.headers là một thể hiện của ActionController::Http::Headers có vẻ như là một Hash. Tôi mong chờ, do đó, các tiêu đề được đánh dấu trên tên tôi gửi. Nếu tôi gửi một yêu cầu tuy nhiên, với một tiêu đề Authorization, như vậy:

curl -H 'Authorization: OAuth realm="MyRealm",...' http://app/path 

Các mã sau trong hành động trả về false:

if request.headers.include?('Authorization') ... 

Trong khi echos sau ra giá trị tôi gửi trong tiêu đề :

render :text => request.headers['Authorization'] 

Vui lòng cung sau trả về true, thú vị đủ:

if request.headers.include?('HTTP_AUTHORIZATION') ... 

Và tương tự, sau đây vang ra giá trị tôi gửi trong tiêu đề:

render :text => request.headers['HTTP_AUTHORIZATION'] 

Có vẻ như có một số kỳ diệu xảy ra mà tôi không biết. Tôi hoàn toàn nhầm lẫn là tại sao việc kiểm tra khoá 'Ủy quyền' không thành công, nhưng việc hiển thị giá trị của request.headers ['Authorization'] thành công. Tôi cũng bối rối về nơi 'HTTP_AUTHORIZATION' đến từ đó là không phải là tên của tiêu đề tôi gửi cùng với yêu cầu. Có ai biết chính xác những gì đang diễn ra không?

+0

Tôi đã dành một giờ trước khi tìm hiểu điều này. Tôi nghĩ rằng nó khá khó hiểu: ít nhất họ nên ghi lại hành vi này tốt hơn. – collimarco

Trả lời

26

Bạn chính xác - phương pháp headers của ActionController::Request trả về phiên bản ActionController::Http::Headers, được kế thừa từ Hash. Nếu chúng ta phá vỡ mở nguồn, chúng tôi thấy điều này:

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 

Vì vậy, khi truy cập vào Hash qua [], có một tấm séc thứ hai để xem nếu giá trị từ env_name (mà chỉ upcases phím và prepends HTTP_) tồn tại.

Đây là lý do tại sao bạn không thể nhận được giá trị thực từ request.headers.include?('Authorization') - include? không được ghi đè trong phân lớp để kiểm tra cả phiên bản tiêu chuẩn và phiên bản upcased của tiêu đề. Tôi tưởng tượng bạn có thể làm theo phù hợp và thực hiện nó cho mình như thế này:

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

Ném đó vào lib/extensions/action_controller.rb hoặc một cái gì đó, yêu cầu nó trong environment.rb nếu cần thiết, và bạn sẽ được tốt để đi. Tôi khuyên bạn nên chỉ thay đổi mã điều khiển của bạn để sử dụng []present? để làm việc kiểm tra, mặc dù :)

Các lý do rằng các tiêu đề được upcased và bắt đầu bằng HTTP_, tôi tin rằng, bắt nguồn từ Rack, Rails' HTTP middleware. Nó có thể làm điều này để giữ impartial về trường hợp, bổ sung thêm HTTP_ để tránh xung đột với các công cụ môi trường không tiêu đề khác mà đi vào.Vì vậy, có, một chút huyền diệu, nhưng không quá khó hiểu sau khi liếc nhìn nguồn, mà tôi luôn luôn khuyên bạn nên :) Rails có một số nguồn rất tốt đẹp mà tôi đã học được rất nhiều từ trong những năm qua.

+0

Cảm ơn Brent! Tôi sẽ tránh né cú đấm và chỉ sử dụng hiện tại? như bạn đề nghị Vẫn còn tò mò về lý do, nhưng bạn đã cho tôi một nơi tốt để bắt đầu tìm kiếm. –

+0

Cảm ơn bạn rất nhiều Brent! Thật khó khăn và kỳ quặc khi Rails tự động viết hoa và nối các tiêu đề bằng 'HTTP_' :( –

4

Theo The Common Gateway Interface RFC:

Meta-biến với tên bắt đầu bằng "HTTP_" chứa các giá trị đọc từ các lĩnh vực tiêu đề yêu cầu khách hàng, nếu giao thức sử dụng là HTTP. Tên trường tiêu đề HTTP được chuyển đổi thành chữ hoa, có tất cả các lần xuất hiện của "-" được thay thế bằng "_" và có "HTTP_" được thêm trước để cung cấp tên biến meta.

Các vấn đề liên quan