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