2009-11-02 66 views
23

Tôi đang duy trì trang web Ruby on Rails và tôi bị nhầm lẫn về cách thực hiện chuyển hướng đến URL tương đối bằng giao thức https.Rails chuyển hướng với https

tôi thành công có thể tạo ra một chuyển hướng đến một URL có liên quan sử dụng http, ví dụ:

redirect_to "/some_directory/" 

Nhưng tôi không thể phân biệt như thế nào để tạo ra một chuyển hướng đến một URL bằng cách sử dụng giao thức https. Tôi đã chỉ có thể làm như vậy bằng cách sử dụng URL tuyệt đối, ví dụ:

redirect_to "https://mysite.com/some_directory/" 

Tôi muốn giữ mã của tôi sạch sẽ, và sử dụng URL tương đối có vẻ như là một ý tưởng tốt. Có ai biết làm thế nào để đạt được điều này trong Rails?

+0

Tôi có thể làm rõ câu hỏi của bạn không. Bạn có muốn buộc mọi người luôn sử dụng HTTPS trên trang web của mình hay chỉ cho một số URL? RAILS mặc định sẽ tiếp tục sử dụng HTTPS nếu yêu cầu hiện tại là HTTPS. – scottd

Trả lời

8

Bạn đang có lẽ tốt hơn bằng cách sử dụng ssl_requirement và không quan tâm nếu một liên kết hoặc redirec t là hoặc không sử dụng https. Với ssl_requirement, bạn khai báo những hành động nào yêu cầu SSL, những hành động nào có khả năng SSL và những cái nào được yêu cầu không sử dụng SSL.

Nếu bạn đang chuyển hướng đến một nơi nào đó bên ngoài ứng dụng Rails, hãy chỉ định giao thức như đề xuất của Olly sẽ hoạt động.

+14

Những ngày này nhìn vào 'force_ssl', có sẵn trong đường ray 3.1 trở lên. –

+3

Matt nếu bạn đưa ra bình luận của bạn một câu trả lời riêng biệt, tôi sẽ bỏ phiếu cho nó. – Spundun

-3

Mở lớp học có redirect_to và thêm phương thức redirect_to_secure_of với cách triển khai thích hợp. Sau đó gọi:

redirect_to_secure_of "/some_directory/" 

Đặt phương pháp này trong lib thư mục hoặc một nơi nào hữu ích.

+0

Xin cảm ơn, nhưng tôi đang tìm kiếm một chút chi tiết hơn "triển khai thích hợp". –

+0

Xin lỗi, tôi nghĩ bạn đã hỏi làm thế nào để làm cho * gọi * mã sạch sẽ. – yfeldblum

-1

URL tương đối, theo định nghĩa, sử dụng giao thức và máy chủ lưu trữ hiện tại. Nếu bạn muốn thay đổi giao thức đang được sử dụng, bạn cần phải cung cấp URL tuyệt đối. Tôi sẽ có được lời khuyên Tư pháp và tạo ra một phương pháp mà thực hiện điều này cho bạn:

def redirect_to_secure(relative_uri) 
    redirect_to "https://" + request.host + relative_uri 
end 
35

Phương pháp ActionController::Base#redirect_to mất một tùy chọn băm, một trong những thông số trong số đó là :protocol mà cho phép bạn gọi:

redirect_to :protocol => 'https://', 
      :controller => 'some_controller', 
      :action => 'index' 

Xem định nghĩa cho #redirect_to#url_for để biết thêm thông tin về các tùy chọn.


Ngoài ra, và đặc biệt là nếu SSL được sử dụng cho tất cả các hành động điều khiển của bạn, bạn có thể tham gia một cách tiếp cận declarative hơn sử dụng một before_filter. Trong ApplicationController bạn có thể xác định các phương pháp sau đây:

def redirect_to_https 
    redirect_to :protocol => "https://" unless (request.ssl? || request.local?) 
end 

Sau đó bạn có thể thêm các bộ lọc trong những bộ điều khiển của bạn mà có hành động đòi hỏi SSL, ví dụ:

class YourController 
    before_filter :redirect_to_https, :only => ["index", "show"] 
end 

Hoặc, nếu bạn yêu cầu SSL trên toàn bộ ứng dụng của bạn , tuyên bố bộ lọc trong ApplicationController:

class ApplicationController 
    before_filter :redirect_to_https 
end 
+0

Bạn có thể sử dụng ': protocol => 'https: //'' iff bạn đang chuyển băm sang 'redirect_to' nếu bạn đang chuyển một URL tương đối như trong câu hỏi trên, điều đó sẽ không hoạt động. Tôi đồng ý rằng một 'before_filter' là cách tốt hơn để đi nói chung. –

3

Nếu bạn muốn kiểm soát toàn cầu giao thức của các url được tạo trong bộ điều khiển, bạn có thể ghi đè lên phương thức url_options trong bộ điều khiển ứng dụng của bạn.Bạn có thể buộc các giao thức của các url được tạo ra tùy thuộc vào đường ray env như vậy:

def url_options 
    super 
    @_url_options.dup.tap do |options| 
     options[:protocol] = Rails.env.production? ? "https://" : "http://" 
     options.freeze 
    end 
    end 

ví dụ này làm việc trong đường ray 3.2.1, tôi không chắc chắn chính xác cho các phiên bản trước đó hoặc trong tương lai.

23

Nếu bạn muốn toàn bộ ứng dụng của bạn để được phục vụ trên https sau đó kể từ Rails 4.0 cách tốt nhất để làm điều này là để cho phép force_ssl trong file cấu hình như vậy:

# config/environments/production.rb 
Rails.application.configure do 
    # [..] 

    # Force all access to the app over SSL, use Strict-Transport-Security, 
    # and use secure cookies. 
    config.force_ssl = true 
end 

Theo mặc định này tùy chọn đã có trong config/environments/production.rb trong các ứng dụng mới được tạo nhưng đã được nhận xét.

Khi nhận xét cho biết, điều này sẽ không chỉ chuyển hướng đến https, mà còn đặt tiêu đề Strict-Transport-Security (HSTS) và đảm bảo rằng cờ an toàn được đặt trên tất cả cookie. Cả hai biện pháp làm tăng tính bảo mật của ứng dụng của bạn mà không có những hạn chế đáng kể. Nó sử dụng ActionDispatch:SSL.

Cài đặt HSTS hết hạn được đặt thành một năm theo mặc định và không bao gồm tên miền phụ, có thể là tốt cho hầu hết các ứng dụng. Bạn có thể cấu hình này với hsts tùy chọn:

config.hsts = { 
    expires: 1.month.to_i, 
    subdomains: false, 
} 

Nếu bạn đang chạy Rails 3 (> = 3.1) hoặc không muốn sử dụng https cho toàn bộ ứng dụng, sau đó bạn có thể sử dụng phương pháp force_ssl trong bộ điều khiển:

class SecureController < ApplicationController 
    force_ssl 
end 

Đó là tất cả. Bạn có thể đặt nó trên mỗi bộ điều khiển hoặc trong số ApplicationController. Bạn có thể buộc https có điều kiện bằng cách sử dụng các tùy chọn if hoặc unless quen thuộc; ví dụ:

# Only when we're not in development or tests 
force_ssl unless: -> { Rails.env.in? ['development', 'test'] } 
+0

force_ssl không phải là một lựa chọn tuyệt vời nếu bạn đang phát triển phía sau một đường hầm. Ví dụ, một đường hầm ngrok tls cho phép bạn chỉ định một cert. Sau đó ngrok chấm dứt kết nối tls với cert được chỉ định và chuyển tiếp không được mã hóa vào ứng dụng của bạn (vì vậy ứng dụng của bạn cho rằng mọi thứ đều là http). Điều này có nghĩa là bạn không phải thiết lập proxy nginx và làm https trên hộp phát triển của bạn. –

+0

@MichaelJohnston Đây là lý do tại sao bạn có thể sử dụng 'trừ' để không buộc SSL trong dev (xem dòng cuối cùng trong câu trả lời của tôi). – Carpetsmoker

2

Trong Rails 4 người ta có thể sử dụng force_ssl_redirect before_action để thực thi ssl cho một bộ điều khiển duy nhất. Xin lưu ý rằng bằng cách sử dụng phương pháp này, cookie của bạn sẽ không được đánh dấu là an toàn và không sử dụng HSTS.

+0

Bạn có thể xây dựng câu cuối cùng không? Đối với một người không quen với 'đánh dấu cookie là an toàn' và HSTS. –

1

Câu trả lời này phần nào tiếp tuyến với câu hỏi ban đầu, nhưng tôi ghi lại câu hỏi này trong trường hợp những người khác kết thúc ở đây trong các trường hợp tương tự với bản thân mình.

Tôi có một tình huống mà tôi cần phải có Rails sử dụng https proto trong url helpers, vv mặc dù nguồn gốc của tất cả các yêu cầu không được mã hóa (http).

Hiện tại, thông thường trong trường hợp này (bình thường khi Rails nằm sau proxy ngược hoặc bộ cân bằng tải vv), tiêu đề x-forwarded-proto được đặt bởi proxy ngược hoặc bất kỳ thứ gì, vì vậy mặc dù yêu cầu không được mã hóa giữa proxy & đường ray (có lẽ không được khuyến khích trong sản xuất bằng cách này) đường ray nghĩ rằng tất cả mọi thứ là trong https.

Tôi cần chạy phía sau đường hầm ngrok tls. Tôi muốn có ngrok chấm dứt các tls với allowencrypt giấy chứng nhận tôi chỉ định. Tuy nhiên khi nó làm như vậy, ngrok không cung cấp khả năng tùy chỉnh tiêu đề, bao gồm thiết lập x-forwarded-proto (mặc dù tính năng này được lên kế hoạch tại một số điểm trong tương lai).

Giải pháp hóa ra khá đơn giản: Đường ray không phụ thuộc vào giao thức xuất xứ hoặc liệu x-forwarded-proto được đặt trực tiếp, nhưng trên Rack env var rack.url_scheme. Vì vậy, tôi chỉ cần thêm phần trung gian Rack này vào phát triển:

class ForceUrlScheme 
    def initialize(app) 
    @app = app 
    end 

    def call(env) 
    env['rack.url_scheme'] = 'https' 
    @app.call(env) 
    end 
end 
Các vấn đề liên quan