【问题标题】:Rails 3 SSL routing redirects from https to httpRails 3 SSL 路由从 https 重定向到 http
【发布时间】:2011-04-28 23:07:08
【问题描述】:

这个问题与这个SO question and answer (rails-3-ssl-deprecation ) 相关,它建议使用 routes.rb 和类似的路由来处理 rails 3 中的 ssl:

resources :sessions, :constraints => { :protocol => "https" }

# Redirect /foos and anything starting with /foos/ to https.
match "foos(/*path)", :to => redirect { |_, request|  "https://" + request.host_with_port + request.fullpath }

我的问题是链接使用相对路径(我认为这是正确的术语),一旦我在 https 页面上,所有其他指向网站上其他页面的链接都使用 https。

1) 对于不需要 https 的页面,返回 http 的最佳方式是什么?我是否必须为所有这些设置重定向(我希望注意)或者有更好的方法。重定向会是这样吗:

match "foos(/*path)", :to => redirect { |_, request|  "http://" + request.host_with_port + request.fullpath }

2) 如果需要重定向回 http,我如何处理我希望所有方法都为 http 的情况,除了一个?即 foos(/*path) 将适用于所有 foos 方法。但是假设我希望 foos/upload_foos 使用 ssl。我知道如何要求它

scope :constraints => { :protocol => "https" } do
  match 'upload_foos' => 'foos#upload_foos', :via => :post, :as => :upload_foos 
end

但是如果我将 http 重定向到 foos 路径,https upload_foos 会发生什么?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3


    【解决方案1】:

    如果您希望所有链接都能够在 http 和 https 之间切换,则必须停止使用 _path 助手并切换到 _url 助手。

    之后,使用强制协议参数和协议约束的范围使url自动切换。

    routes.rb
    scope :protocol => 'https://', :constraints => { :protocol => 'https://' } do
      resources :sessions
    end
    
    resources :gizmos
    

    现在在你看来:

    <%= sessions_url # => https://..../sessions %>
    <%= gizmos_url   # => http://..../gizmos %>
    

    编辑

    当您在 https 中时,这不会修复返回到 http 的 url。要解决这个问题,您需要覆盖 url_for

    在任何帮手
    module ApplicationHelper
      def url_for(options = nil)
        if Hash === options
          options[:protocol] ||= 'http'
        end
        super(options)
      end
    end
    

    这会将协议设置为“http”,除非它被明确设置(在路由中或调用帮助程序时)。

    【讨论】:

    • 非常感谢您的回复。对我来说,它的工作从 http 到 https 但不会再回来。使用您的示例:当在 http gizmos 页面上时,所有链接都是 http,而不是会话,这是正确的 https。如果我转到 https 会话页面,所有其他链接都变为 https,包括指向 gizmos 的链接,即使所有链接都使用 _url 帮助程序。有任何想法吗?我也不确定当只有少数需要 https 时,我是否喜欢对网站上的所有链接使用 _url 帮助器。
    • 是的,您还需要在所有其他路由器周围添加scope :protocol =&gt; 'http://' do end。这样,助手使用 http 而不是 https。您必须使用 _url 助手,因为它们会生成完整的 url,而 _path 助手只会生成路径。
    • 当我这样做时,除了在根页面上时,其他路由都不起作用。根 :to => "gizmos#index"。如果我在该根页面上,所有链接都显示正确,但在任何其他页面 http 或 https 上,当它尝试使用 url 帮助程序创建链接时,我现在会遇到路由错误。例如。没有路线匹配 {:controller=>"gizmos", :action=>"create"}
    • 找到了解决方案。从您的路线中删除 scope :protocol =&gt; 'http://' 并在我的编辑中添加帮助程序。
    • 这行得通,谢谢塞缪尔。我遇到的最后一个问题是,当我转到主页时(root :to => "gizmos#index"),我被重定向到 https 登录页面,这就是我想要的。登录后,我会被带到根页面,但它是 https 而不是 http。有没有办法编写使它成为 http 的根路由?
    【解决方案2】:

    这是很久以前的事了,我确信它可以改进,但回到某些旧版本的 rails,我在应用程序控制器中有此代码。不确定这对 Rails 3 是否仍然有效,但它可能会有所帮助:

    private
      SECURE_ACTIONS = {
        :login => ["login", "login_customer", "remind_password", "add_customer", "add_or_login_customer"], 
        :store => ["checkout", "save_order"],
        :order => ["show"] }
    
      # Called as a before_filter in controllers that have some https:// actions
      def require_ssl
        unless ENV['RAILS_ENV'] != 'production' or  @request.ssl?
          redirect_to :protocol => 'https://', :action => action_name
          # we don't want to continue with the action, so return false from the filter
          return false
        end
      end
    
    def default_url_options(options)
        defaults = {}    
    
        if USE_EXPLICIT_HOST_IN_ALL_LINKS
          # This will OVERRIDE only_path => true, not just set the default.
          options[:only_path] = false
          # Now set the default protocol appropriately:
          if actions = SECURE_ACTIONS[ (options[:controller] || controller_name).to_sym ] and 
             actions.include? options[:action]
    
            defaults[:protocol] = 'https://'
            defaults[:host] = SECURE_SERVER if defined? SECURE_SERVER
          else
            defaults[:protocol] = 'http://'
            defaults[:host] = NON_SECURE_SERVER if defined? NON_SECURE_SERVER
          end
        end
        return defaults
      end
    

    USE_EXPLICIT_HOST_IN_ALL_LINKS 是一些全局配置选项,但您可以忽略它。

    在每个需要 https 的控制器中,我将添加 before_filter :require_ssl 并将该控制器名称及其方法添加到 SECURE_ACTIONS。这可能可以通过将操作名称传递给 before 过滤器或其他方式来改进。

    【讨论】:

    • 感谢您的回复。我喜欢您如何在一个地方指定所有安全操作。它使安全的内容变得清晰明了。如果其他答案不起作用,我一定会在我的 rails 3 应用程序中试一试。
    猜你喜欢
    • 1970-01-01
    • 2019-05-17
    • 2011-11-13
    • 2011-05-27
    • 2013-11-02
    • 2012-10-25
    • 2015-01-01
    • 2016-05-26
    • 2017-03-26
    相关资源
    最近更新 更多