Rails перенаправляет с https - PullRequest
27 голосов
/ 02 ноября 2009

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

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

redirect_to "/some_directory/"

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

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

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

Ответы [ 8 ]

37 голосов
/ 03 ноября 2009

Метод 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
30 голосов
/ 15 октября 2014

Если вы хотите, чтобы ваше все приложение обслуживалось по протоколу 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. Вы можете принудительно установить https, используя знакомые опции if или unless; например:

# Only when we're not in development or tests
force_ssl unless: -> { Rails.env.in? ['development', 'test'] }
11 голосов
/ 03 ноября 2009

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

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

3 голосов
/ 24 апреля 2017

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

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

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

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

Решение оказалось довольно простым: 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
2 голосов
/ 14 апреля 2015

В Rails 4 можно использовать force_ssl_redirect before_action для принудительного применения ssl для одного контроллера. Обратите внимание, что при использовании этого метода ваши куки не будут помечены как безопасные и HSTS не используется.

2 голосов
/ 06 марта 2012

Если вы хотите глобально управлять протоколом URL, сгенерированным в контроллерах, вы можете переопределить метод url_options в вашем контроллере приложения. Вы можете заставить протокол сгенерированных URL-адресов в зависимости от 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, я не совсем уверен в более ранних или будущих версиях.

0 голосов
/ 02 ноября 2009

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

def redirect_to_secure(relative_uri)
  redirect_to "https://" + request.host + relative_uri
end
0 голосов
/ 02 ноября 2009

Откройте класс с redirect_to и добавьте метод redirect_to_secure_of с соответствующей реализацией. Затем позвоните:

redirect_to_secure_of "/some_directory/"

Поместите этот метод в каталог lib или куда-нибудь полезное.

...