модуль ActionController::Redirecting
Константы
- ILLEGAL_HEADER_VALUE_REGEX
Открытые методы экземпляра
# File actionpack/lib/action_controller/metal/redirecting.rb, line 169 def redirect_back(fallback_location:, allow_other_host: _allow_other_host, **args) redirect_back_or_to fallback_location, allow_other_host: allow_other_host, **args end
Устаревший псевдоним с мягким переходом к redirect_back_or_to, в котором местоположение fallback_location передается как именованный аргумент, а не как первый позиционный аргумент.
# File actionpack/lib/action_controller/metal/redirecting.rb, line 196
def redirect_back_or_to(fallback_location, allow_other_host: _allow_other_host, **options)
if request.referer && (allow_other_host || _url_host_allowed?(request.referer))
redirect_to request.referer, allow_other_host: allow_other_host, **options
else
# The method level `allow_other_host` doesn't apply in the fallback case, omit
# and let the `redirect_to` handling take over.
redirect_to fallback_location, **options
end
end Перенаправляет браузер на страницу, с которой был отправлен запрос (источник перехода), если это возможно; в противном случае перенаправляет на указанное резервное местоположение по умолчанию.
Информация об источнике перехода извлекается из заголовка HTTP Referer (sic) запроса. Этот заголовок необязателен, и его наличие в запросе зависит от настроек безопасности браузера и предпочтений пользователя. Если в запросе отсутствует этот заголовок, будет использовано fallback_location.
redirect_back_or_to({ action: "show", id: 5 })
redirect_back_or_to @post
redirect_back_or_to "http://www.rubyonrails.org"
redirect_back_or_to "/images/screenshot.jpg"
redirect_back_or_to posts_url
redirect_back_or_to proc { edit_post_url(@post) }
redirect_back_or_to '/', allow_other_host: false
Параметры
-
:allow_other_host— разрешает или запрещает перенаправление на хост, отличный от текущего; по умолчанию — true.
Все остальные параметры, которые можно передать в redirect_to, принимаются, и поведение остается таким же.
# File actionpack/lib/action_controller/metal/redirecting.rb, line 150
def redirect_to(options = {}, response_options = {})
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
allow_other_host = response_options.delete(:allow_other_host)
proposed_status = _extract_redirect_to_status(options, response_options)
redirect_to_location = _compute_redirect_to_location(request, options)
_ensure_url_is_http_header_safe(redirect_to_location)
self.location = _enforce_open_redirect_protection(redirect_to_location, allow_other_host: allow_other_host)
self.response_body = ""
self.status = proposed_status
end Перенаправляет браузер на целевой адрес, указанный в options. Этим параметром может быть один из следующих вариантов:
-
Hash— URL будет сформирован вызовом url_for с помощьюoptions. -
Record— URL будет сформирован вызовом url_for с помощьюoptions, который ссылается на именованный URL для этой записи. -
String, начинающаяся сprotocol://(например,http://), или ссылка с относительным протоколом (например,//) — передается напрямую как целевой адрес перенаправления. -
String, не содержащая протокол, — к строке добавляются текущие протокол и хост. -
Proc— блок, который будет выполнен в контексте контроллера. Должен возвращать любой параметр, принимаемый методомredirect_to.
Примеры
redirect_to action: "show", id: 5
redirect_to @post
redirect_to "http://www.rubyonrails.org"
redirect_to "/images/screenshot.jpg"
redirect_to posts_url
redirect_to proc { edit_post_url(@post) }
Если не указано иное с помощью параметра :status, перенаправление выполняется с использованием заголовка 302 Found:
redirect_to post_url(@post), status: :found redirect_to action: 'atom', status: :moved_permanently redirect_to post_url(@post), status: 301 redirect_to action: 'atom', status: 302
Код состояния может быть стандартным кодом состояния HTTP, заданным целым числом, или символом, представляющим описание в нижнем регистре с подчеркиваниями вместо пробелов и преобразованное в символ. Обратите внимание: код состояния должен быть кодом HTTP 3xx, иначе перенаправление не произойдет.
Если вы используете XHR-запросы, отличные от GET и POST, и выполняете перенаправление после запроса, некоторые браузеры будут следовать перенаправлению, используя исходный метод запроса. Это может привести к нежелательному поведению, например, к двойному DELETE. Чтобы обойти эту проблему, можно вернуть код состояния 303 See Other, при котором перенаправление будет выполнено с помощью GET-запроса.
redirect_to posts_url, status: :see_other redirect_to action: 'index', status: 303
Также можно назначить флеш-сообщение при перенаправлении. Для часто используемых имен флеш-сообщений предусмотрены два специальных аксессора: alert и notice, а также универсальное хранилище flash.
redirect_to post_url(@post), alert: "Watch it, mister!"
redirect_to post_url(@post), status: :found, notice: "Pay attention to the road"
redirect_to post_url(@post), status: 301, flash: { updated_post_id: @post.id }
redirect_to({ action: 'atom' }, alert: "Something serious happened")
Инструкции после вызова redirect_to в контроллере продолжают выполняться, поэтому redirect_to не останавливает выполнение функции. Чтобы немедленно завершить выполнение функции после вызова redirect_to, используйте return.
redirect_to post_url(@post) and return
Защита от открытых перенаправлений
По умолчанию Rails защищает ваше приложение от перенаправлений на внешние хосты, известных как открытые перенаправления.
В этом случае redirect_to автоматически проверяет потенциально небезопасный URL:
redirect_to params[:redirect_url]
Параметр конфигурации action_on_open_redirect определяет поведение при обнаружении небезопасного перенаправления: * :log — записывает предупреждение в журнал, но разрешает перенаправление * :notify — отправляет уведомление Active Support для мониторинга * :raise — вызывает исключение UnsafeRedirectError
Чтобы разрешить любые перенаправления на внешние адреса, передайте allow_other_host: true, хотя использовать в этом случае параметр, предоставленный пользователем, небезопасно.
redirect_to "https://rubyonrails.org", allow_other_host: true
Подробнее о том, что считается внутренним и безопасным URL, а также о том, как задать альтернативный URL перенаправления на случай небезопасного адреса, см. в разделе url_from.
Защита от перенаправлений на относительные пути URL
Rails также защищает от потенциально небезопасных перенаправлений на относительные пути URL, не начинающиеся с косой черты. Они могут создавать уязвимости в системе безопасности:
redirect_to "example.com" # Creates http://yourdomain.comexample.com
redirect_to "@attacker.com" # Creates http://yourdomain.com@attacker.com
# which browsers interpret as user@host
Можно настроить обработку этих случаев в Rails с помощью следующих параметров:
config.action_controller.action_on_path_relative_redirect = :log # default config.action_controller.action_on_path_relative_redirect = :notify config.action_controller.action_on_path_relative_redirect = :raise
-
:log— записывает предупреждение в журнал, но разрешает перенаправление -
:notify— отправляет уведомление Active Support, но разрешает перенаправление (включает трассировку стека, помогающую определить источник) -
:raise— вызывает исключениеUnsafeRedirectError
# File actionpack/lib/action_controller/metal/redirecting.rb, line 254 def url_from(location) location = location.presence location if location && _url_host_allowed?(location) end
Проверяет, является ли переданный location внутренним URL, на который безопасно перенаправлять, и возвращает его; в противном случае возвращает nil. Полезно обернуть URL перенаправления, заданный параметром, и указать альтернативный URL для перенаправления:
redirect_to url_from(params[:redirect_url]) || root_url
location считается внутренним и безопасным, если он принадлежит тому же хосту, что и request.host:
# If request.host is example.com:
url_from("https://example.com/profile") # => "https://example.com/profile"
url_from("http://example.com/profile") # => "http://example.com/profile"
url_from("http://evil.com/profile") # => nil
Поддомены считаются частью хоста:
# If request.host is on https://example.com or https://app.example.com, you'd get:
url_from("https://dev.example.com/profile") # => nil
ПРИМЕЧАНИЕ: этот метод похож на url_for, который генерирует внутренний URL на основе различных параметров приложения, например url_for(@post). Однако url_from предназначен для проверки внешнего параметра, например url_from(params[:redirect_url]).
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.