Rails重定向与https

我正在维护一个Ruby on Rails站点,我对如何使用https协议重定向到相对URL感到困惑。

我可以使用http成功创建重定向到相对URL,例如:

redirect_to "/some_directory/" 

但我无法辨别如何使用https协议创建重定向到URL。 我只能通过使用绝对URL来实现,例如:

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

我想保持我的代码干净,使用相对URL似乎是个好主意。 有谁知道如何在Rails中实现这一目标?

你可能最好不要使用ssl_requirement而不关心链接或重定向是否使用https。 使用ssl_requirement,您可以声明哪些操作需要SSL,哪些操作需要SSL以及哪些操作不需要使用SSL。

如果您在Rails应用程序之外的某个位置重定向,那么将协议指定为Olly建议将起作用。

ActionController::Base#redirect_to方法接受一个选项哈希,其中一个参数是:protocol允许你调用的:protocol

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

有关选项的更多信息,请参阅#redirect_to#url_for的定义。


或者,特别是如果要将SSL用于所有控制器操作,您可以使用before_filter采用更具说明性的方法。 在ApplicationController您可以定义以下方法:

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

然后,您可以在那些具有需要SSL的操作的控制器中添加filter,例如:

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

或者,如果您需要在整个应用程序中使用SSL,请在ApplicationController声明filter:

 class ApplicationController before_filter :redirect_to_https end 

如果您希望通过https提供整个应用程序 ,那么从Rails 4.0开始 ,最好的方法是在配置文件中启用force_ssl ,如下所示:

 # 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 

默认情况下,此选项已存在于新生成的应用程序中的config/environments/production.rb中,但已注释掉。

正如评论所说,这不仅会重定向到https,还会设置Strict-Transport-Security标头( HSTS ),并确保在所有Cookie上设置安全标志。 这两项措施都可以提高应用程序的安全性而不会有明显的缺 它使用ActionDispatch:SSL

HSTS过期设置默认设置为一年,不包括子域,这对大多数应用程序来说可能都很好。 您可以使用hsts选项配置它:

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

如果您正在运行Rails 3(> = 3.1)或者不想对整个应用程序使用https,那么您可以在控制器中使用force_ssl方法:

 class SecureController < ApplicationController force_ssl end 

就这样。 您可以为每个控制器或ApplicationController设置它。 您可以使用熟悉的ifunless选项有条件地强制使用https; 例如:

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

如果要全局控制在控制器中生成的URL协议,可以覆盖应用程序控制器中的url_options方法。 您可以强制生成的URL的协议取决于rails env,如下所示:

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

这个例子适用于rails 3.2.1,我不确定早期或未来的版本。

在Rails 4中,可以使用force_ssl_redirect before_action为单个控制器强制执行ssl。 请注意,使用此方法,您的cookie不会被标记为安全,并且不会使用HSTS 。

这个答案与原始问题有些相似,但我会记录下来,以防其他人在类似情况下结束此事。

我有一种情况,我需要让Rails在url helpers等中使用https proto,即使所有请求的来源都是未加密的( http )。

现在,通常在这种情况下(当Rails在反向代理或负载均衡器之后时是正常的), x-forwarded-proto报头由反向代理或其他任何设置,因此即使请求在代理和请求之间未加密rails(在生产中可能不建议使用)rails认为一切都在https

我需要在一个ngrok tls隧道后面跑。 我想让ngrok使用我指定的letsencrypt证书终止tls。 但是,当它这样做时,ngrok不提供自定义标头的function,包括设置x-forwarded-proto (尽管此function计划在将来的某个时候)。

解决方案结果非常简单:Rails不依赖于原始协议或是否直接设置x-forwarded-proto ,而是依赖于Rack env var rack.url_scheme 。 所以我只需要在开发中添加这个Rack中间件:

 class ForceUrlScheme def initialize(app) @app = app end def call(env) env['rack.url_scheme'] = 'https' @app.call(env) end end 

根据定义,相对URL使用当前协议和主机。 如果要更改正在使用的协议,则需要提供绝对URL。 我会采用Justice的建议并创建一个为您完成此操作的方法:

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

打开具有redirect_to的类,并使用适当的实现添加方法redirect_to_secure_of 。 然后打电话:

 redirect_to_secure_of "/some_directory/" 

将此方法放在lib目录或有用的地方。