Подтвердить что ты не робот

Rails перенаправляет с помощью https

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

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

redirect_to "/some_directory/"

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

Метод 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

Ответ 3

Если вы хотите, чтобы все ваше приложение было передано через 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'] }

Ответ 4

Если вы хотите глобально контролировать протокол URL-адресов, созданных в контроллерах, вы можете переопределить метод url_options в своем контроллере приложений. Вы могли бы заставить протокол сгенерированных URL-адресов в зависимости от enils как:

 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

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

Ответ 6

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

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

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

Мне нужно было бежать за туннелем ngrok tls. Я хотел, чтобы ngrok завершал tls с помощью сертификатов letencrypt, которые я указал. Однако, когда это происходит, 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

Ответ 7

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

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

Ответ 8

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

redirect_to_secure_of "/some_directory/"

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