Rails重定向与https

时间:2009-11-02 16:26:07

标签: ruby-on-rails redirect https relative-path

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

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

redirect_to "/some_directory/"

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

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

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

9 个答案:

答案 0 :(得分:37)

ActionController::Base#redirect_to方法采用选项哈希,其中一个参数为: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操作的控制器中添加过滤器,例如:

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

或者,如果您需要在整个应用中使用SSL,请在ApplicationController中声明过滤器:

class ApplicationController
    before_filter :redirect_to_https
end

答案 1 :(得分:29)

如果您希望通过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'] }

答案 2 :(得分:11)

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

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

答案 3 :(得分:3)

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

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

现在,通常在这种情况下(当Rails落后于反向代理或负载均衡器等时这是正常的),x-forwarded-proto标头由反向代理或其他设置,所以即使请求未加密代理人和rails(在生产过程中可能不建议使用)rails认为一切都在https

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

解决方案结果非常简单:Rails不依赖于原始协议或是否直接设置x-forwarded-proto,而是依赖于机架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

答案 4 :(得分:2)

如果要全局控制在控制器中生成的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,我不确定早期版本或未来版本。

答案 5 :(得分:2)

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

答案 6 :(得分:0)

如果您想通过https强制所有流量,那么Rails 6中最好的方法是使用以下命令配置production.rb

config.force_ssl = false

如果您需要更灵活的解决方案,则可以使用简单的before_action过滤器进行处理:

class ApplicationController < ActionController::Base

  include SessionsHelper
  include LandingpageHelper
  include ApplicationHelper
  include UsersHelper
  include OrganisationHelper

  before_action :enforce_ssl, :except => [:health] 

  def enforce_ssl
    if ENV['ENFORCE_SSL'].to_s.eql?('true') && !request.ssl?
      redirect_to request.url.gsub(/http/i, "https")
    end
  end 


end

如果您通过运行状况检查在AWS ECS Fargate上运行应用程序,则您需要一个更灵活的解决方案,因为来自AWS目标组的运行状况检查不会通过https调用。当然,您希望运行状况检查正常进行,同时希望对所有其他控制器方法强制使用SSL。

ENFORCE_SSL只是打开/关闭此功能的环境变量。

答案 7 :(得分:-2)

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

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

答案 8 :(得分:-3)

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

redirect_to_secure_of "/some_directory/"

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