Rails 4 Токен Подлинности
Я работал над новым приложением Rails 4 (на Ruby 2.0.0-p0), когда столкнулся с некоторыми проблемами с токенами подлинности.
При написании контроллера, который отвечает на JSON (используя respond_to
метод класса), я добрался до create
действие, которое я начал получать ActionController::InvalidAuthenticityToken
исключения, когда я пытался создать запись, используя curl
,
Я убедился, что я установил -H "Content-Type: application/json"
и я установил данные с -d "<my data here>"
но все равно не повезло.
Я попытался написать тот же контроллер с использованием Rails 3.2 (на Ruby 1.9.3), и у меня не возникло проблем с токеном подлинности. Я искал вокруг и увидел, что в Rails 4 произошли некоторые изменения с токенами аутентичности. Насколько я понимаю, они больше не вставляются автоматически в формы? Я предполагаю, что это как-то влияет на не-HTML типы контента.
Есть ли способ обойти это без необходимости запрашивать HTML-форму, перехватывая токен аутентификации, а затем отправляя другой запрос с этим токеном? Или я полностью упускаю что-то совершенно очевидное?
Изменить: Я только что попытался создать новую запись в новом приложении Rails 4, используя скаффолд, ничего не меняя, и я столкнулся с той же проблемой, поэтому я думаю, что это не то, что я сделал.
13 ответов
Я думаю, что я только что понял это. Я изменил (новый) по умолчанию
protect_from_forgery with: :exception
в
protect_from_forgery with: :null_session
согласно комментарию в ApplicationController
,
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
Вы можете увидеть разницу, посмотрев на источник request_forgery_protecton.rb
или, более конкретно, следующие строки:
В Rails 3.2:
# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
reset_session
end
В Rails 4:
def handle_unverified_request
forgery_protection_strategy.new(self).handle_unverified_request
end
Который будет называть следующее:
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end
Вместо того, чтобы отключить защиту csrf, лучше добавить следующую строку кода в форму
<%= tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %>
и если вы используете form_for или form_tag для генерации формы, то она автоматически добавит вышеуказанную строку кода в форму
Добавление следующей строки в форму работало для меня:
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Я не думаю, что хорошо вообще отключать защиту CSRF, если вы не используете исключительно API.
Просматривая документацию по Rails 4 API для ActionController, я обнаружил, что вы можете отключить защиту от подделки для каждого контроллера или для каждого метода.
Например, чтобы отключить защиту CSRF для методов, которые вы можете использовать
class FooController < ApplicationController
protect_from_forgery except: :index
Наткнулся на ту же проблему. Исправлено, добавив в мой контроллер:
skip_before_filter :verify_authenticity_token, if: :json_request?
Ты пробовал?
protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format.json? }
В этом официальном документе рассказывается о том, как правильно отключить защиту от мошенничества для API http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
Это функция безопасности в Rails. Добавьте эту строку кода в форму:
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Документацию можно найти здесь: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
Эти функции были добавлены в целях безопасности и защиты от подделки.
Однако, чтобы ответить на ваш вопрос, вот некоторые материалы. Вы можете добавить эти строки после вашего имени контроллера.
Вот так,
class NameController < ApplicationController
skip_before_action :verify_authenticity_token
Вот несколько строк для разных версий рельсов.
Рельсы 3
skip_before_filter: verify_authenticity_token
Рельсы 4:
skip_before_action: verify_authenticity_token
Если вы намереваетесь отключить эту функцию безопасности для всех подпрограмм контроллера, вы можете изменить значение protect_from_forgery на :null_session в вашем файле application_controller.rb.
Вот так,
class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session
end
Если вы используете jQuery с rails, будьте осторожны, разрешив вход в методы без проверки токена подлинности.
JQuery-UJS может управлять токенами для вас
Он должен быть уже в составе гема jquery-rails, но вам может понадобиться включить его в application.js с
//= require jquery_ujs
Это все, что вам нужно - теперь ваш Ajax-вызов должен работать
Для получения дополнительной информации см.: https://github.com/rails/jquery-ujs
Когда вы определяете свою собственную html-форму, вы должны включить строку токена аутентификации, которая должна быть отправлена на контроллер по соображениям безопасности. Если вы используете rails form helper для генерации токена подлинности, он добавляется в форму следующим образом.
<form accept-charset="UTF-8" action="/login/signin" method="post">
<div style="display:none">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
</div>
...
</form>
Таким образом, решение проблемы состоит в том, чтобы либо добавить поле authenticity_token, либо использовать помощники по рельсам, а не ставить под угрозу безопасность и т. Д.
Все мои тесты работали нормально. Но по какой-то причине я установил переменную среды non-test:
export RAILS_ENV=something_non_test
Я забыл сбросить эту переменную, из-за которой я начал получать ActionController::InvalidAuthenticityToken
исключение.
После сброса $RAILS_ENV
мои тесты снова начали работать.