Ruby-on-rails Rails 使用 https 重定向

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1662262/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:54:33  来源:igfitidea点击:

Rails redirect with https

ruby-on-railsredirecthttpsrelative-path

提问by Brian D'Astous

I'm maintaining a Ruby on Rails site and I'm confused as to how to perform redirects to relative URLs using the https protocol.

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

I can successfully create a redirect to a relative URL using http, for example:

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

redirect_to "/some_directory/"

But I cannot discern how to create a redirect to a URL using the https protocol. I have only been able to do so by using absolute URLS, for example:

但我无法辨别如何使用 https 协议创建指向 URL 的重定向。我只能通过使用绝对 URL 来做到这一点,例如:

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

I would like to keep my code clean, and using relative URLs seems like a good idea. Does anyone know how to achieve this in Rails?

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

采纳答案by Andy Gaskell

You're probably better off using ssl_requirementand not caring if a link or redirect is or isn't using https. With ssl_requirement, you declare which actions require SSL, which ones are capable of SSL and which ones are required not to use SSL.

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

If you're redirecting somewhere outside of your Rails app, then specifying the protocol as Olly suggests will work.

如果您要重定向到 Rails 应用程序之外的某个地方,那么按照 Olly 的建议指定协议就可以了。

回答by Olly

The ActionController::Base#redirect_tomethod takes an options hash, one of the parameters of which is :protocolwhich allows you to call:

ActionController::Base#redirect_to方法采用选项散列,其中一个参数:protocol允许您调用:

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

See the definition for #redirect_toand #url_forfor more info on the options.

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



Alternatively, and especially if SSL is to be used for all your controller actions, you could take a more declarative approach using a before_filter. In ApplicationControlleryou could define the following method:

或者,特别是如果 SSL 用于您的所有控制器操作,您可以使用before_filter. 在ApplicationController你可以定义下面的方法:

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

You can then add filters in your those controllers which have actions requiring SSL, e.g:

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

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

Or, if you require SSL across your entire app, declare the filter in ApplicationController:

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

class ApplicationController
    before_filter :redirect_to_https
end

回答by Martin Tournoij

If you want your entire applicationto be served over https then since Rails 4.0the best way to do this is to enable force_sslin the configuration file like so:

如果您希望整个应用程序都通过 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

By default this option is already present in config/environments/production.rbin in newly generated apps, but is commented out.

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

As the comment says, this will not just redirect to https, but also sets the Strict-Transport-Securityheader (HSTS) and makes sure that the secure flag is set on all cookies. Both measures increase the security of your application without significant drawbacks. It uses ActionDispatch:SSL.

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

The HSTS expire settings are set to a year by default and doesn't include subdomains, which is probably fine for most applications. You can configure this with the hstsoption:

HSTS 过期设置默认设置为一年,不包括子域,这对于大多数应用程序来说可能没问题。您可以使用以下hsts选项进行配置:

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


If you're running Rails 3 (>=3.1)or don't want to use https for the entire application, then you can use the force_sslmethod in a controller:

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

class SecureController < ApplicationController
  force_ssl
end

That's all. You can set it per controller, or in your ApplicationController. You can force https conditionally using the familiar ifor unlessoptions; for example:

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

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

回答by Michael Johnston

This answer is somewhat tangential to the original question, but I record it in case others end up here in similar circumstances to myself.

这个答案与原始问题有些相关,但我将其记录下来,以防其他人在与我类似的情况下最终来到这里。

I had a situation where I needed to have Rails use httpsproto in url helpers etc. even though the origin of all requests is unencrypted (http).

我遇到过需要让 Railshttps在 url helpers 等中使用proto的情况,即使所有请求的来源都未加密 ( http)。

Now, ordinarily in this situation (which is normal when Rails is behind a reverse proxy or load balancer etc.), the x-forwarded-protoheader is set by the reverse proxy or whatever, so even though requests are unencrypted between the proxy & rails (probably not advisable in production by the way) rails thinks everything is in https.

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

I needed to run behind an ngrok tls tunnel. I wanted to have ngrok terminate the tls with letsencrypt certificates I specified. However when it does so, ngrok does not offer the ability to customize headers, including setting x-forwarded-proto(although this feature is planned at some point in the future).

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

The solution turned out to be quite simple: Rails does not depend on either the protocol of the origin or whether x-forwarded-protois set directly, but on the Rack env var rack.url_scheme. So I just needed to add this Rack middleware in development:

结果证明解决方案非常简单: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

回答by Samuel

In Rails 4 one can use the force_ssl_redirectbefore_action to enforce ssl for a single controller. Please note that by using this method your cookies won't be marked as secure and HSTSis not used.

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

回答by Shamu

If you want to globally controll the protocol of urls generated in controllers, you can override the url_options method in you application controller. You could force the protocol of the generated urls depending on the rails env like so :

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

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

this example works in rails 3.2.1, i'm not exactly sure for earlier or future versions.

此示例适用于 rails 3.2.1,我不确定是否适用于早期或未来版本。

回答by Michael Sepcot

Relative URLs, by definition, use the current protocol and host. If you want to change the protocol being used, you need to supply the absolute URL. I would take Justice's advice and create a method that does this for you:

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

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

回答by yfeldblum

Open the class that has redirect_toand add a method redirect_to_secure_ofwith an appropriate implementation. Then call:

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

redirect_to_secure_of "/some_directory/"

Put this method in the libdirectory or somewhere useful.

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