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?
Ответы
Ответ 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
или где-нибудь полезный.