Перенаправление Rails с помощью https

Я поддерживаю сайт Ruby on Rails, и я смущен тем, как выполнять перенаправления на относительные URL-адреса с помощью протокола https.

Я могу успешно создать перенаправление на относительный URL с помощью http, например:

redirect_to "/some_directory/"

но я не могу понять, как создать перенаправление на URL-адрес с помощью протокола https. Я смог сделать это только с помощью абсолютных URL-адресов, например:

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

Я хотел бы сохранить свой код в чистоте и использовать относительный URLs кажется хорошей идеей. Кто-нибудь знает, как достичь этого в Rails?

8 ответов


вам, вероятно, лучше использовать ssl_requirement и не заботясь, если ссылка или перенаправление использует или не использует https. С помощью ssl_requirement вы объявляете, какие действия требуют SSL, какие из них способны SSL и какие из них не должны использовать SSL.

Если вы перенаправляете где-то вне своего приложения Rails, то указание протокола, как предлагает Олли, будет работать.


на 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, e.g:

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

или, если вам требуется SSL во всем приложении, объявите фильтр в ApplicationController:

class ApplicationController
    before_filter :redirect_to_https
end

если вы хотите приложение для обслуживания по https, то с рельсы 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 in во вновь созданных приложениях, но закомментирован.

как говорится в комментарии, это не просто перенаправит на https, но и установит (HSTS) и гарантирует, что флажок secure установлен на всех файлах cookies. Обе меры повышают безопасность вашего приложения без существенных недостатков. Он использует ActionDispatch:SSL.

параметры истечения срока действия HSTS по умолчанию установлены на год и не включают поддомены, что, вероятно, нормально для большинства приложений. Вы можете настроить это с помощью :

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

если вы используете рельсы 3 (>=3.1) или не хотите использовать HTTPS для всего приложение, то вы можете использовать force_ssl метод в контроллере:

class SecureController < ApplicationController
  force_ssl
end

вот и все. Вы можете установить его на контроллер или в свой ApplicationController. Вы можете принудительно использовать https условно, используя знакомый if или unless параметры; например:

# 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 для одного контроллера. Обратите внимание, что при использовании этого метода ваши cookies не будут помечены как безопасные и HSTS не используется.


этот ответ несколько касателен к исходному вопросу, но я записываю его на случай, если другие окажутся здесь в аналогичных обстоятельствах для меня.

у меня была ситуация, когда мне нужно было использовать рельсы https proto в помощниках url и т. д. хотя происхождение все запросы шифруются (http).

теперь, обычно в этой ситуации (что нормально, когда Rails находится за обратным прокси или балансировщиком нагрузки и т. д.), the x-forwarded-proto заголовок устанавливается обратным прокси или что бы ни было, поэтому, хотя запросы незашифрованы между прокси и rails (вероятно, не рекомендуется в производстве, кстати) rails думает, что все в https.

мне нужно было бежать за туннелем ngrok tls. Я хотел, чтобы ngrok прекратил tls с сертификатами letsencrypt, которые я указал. Однако, когда это происходит, ngrok не предлагает возможность настраивать заголовки, включая setting x-forwarded-proto (хотя эта функция планируется в какой-то момент будущий.)

решение оказалось довольно простым: рельсы не зависят ни от протокола происхождения, ни от того,x-forwarded-proto устанавливается непосредственно, но на стойке env var rack.url_scheme. Поэтому мне просто нужно было добавить это промежуточное ПО стойки в разработке:

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

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

относительные URL-адреса, по определению, используют текущий протокол и хост. Если вы хотите изменить используемый протокол,необходимо указать абсолютный URL-адрес. Я бы воспользовался советом Джастиса и создал метод, который делает это для вас:

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 каталог или где-то полезно.