рельсы - InvalidAuthenticityToken для запросов json / xml - PullRequest
20 голосов
/ 07 августа 2009

По какой-то причине я получаю InvalidAuthenticityToken при отправке запросов в мое приложение при использовании json или xml. Насколько я понимаю, рельсы должны требовать токен подлинности только для запросов html или js, и поэтому я не должен сталкиваться с этой ошибкой. Единственное решение, которое я нашел до сих пор, это отключение protect_from_forgery для любого действия, к которому я хотел бы получить доступ через API, но это не идеально по очевидным причинам. Мысли

    def create
    respond_to do |format|
        format.html
        format.json{
            render :json => Object.create(:user => @current_user, :foo => params[:foo], :bar => params[:bar])
        }
        format.xml{
            render :xml => Object.create(:user => @current_user, :foo => params[:foo], :bar => params[:bar])
        }
    end
end

и вот что я получаю в журналах всякий раз, когда передаю запрос на действие:

 Processing FooController#create to json (for 127.0.0.1 at 2009-08-07 11:52:33) [POST]
 Parameters: {"foo"=>"1", "api_key"=>"44a895ca30e95a3206f961fcd56011d364dff78e", "bar"=>"202"}

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
  thin (1.2.2) lib/thin/connection.rb:76:in `pre_process'
  thin (1.2.2) lib/thin/connection.rb:74:in `catch'
  thin (1.2.2) lib/thin/connection.rb:74:in `pre_process'
  thin (1.2.2) lib/thin/connection.rb:57:in `process'
  thin (1.2.2) lib/thin/connection.rb:42:in `receive_data'
  eventmachine (0.12.8) lib/eventmachine.rb:242:in `run_machine'
  eventmachine (0.12.8) lib/eventmachine.rb:242:in `run'
  thin (1.2.2) lib/thin/backends/base.rb:57:in `start'
  thin (1.2.2) lib/thin/server.rb:156:in `start'
  thin (1.2.2) lib/thin/controllers/controller.rb:80:in `start'
  thin (1.2.2) lib/thin/runner.rb:174:in `send'
  thin (1.2.2) lib/thin/runner.rb:174:in `run_command'
  thin (1.2.2) lib/thin/runner.rb:140:in `run!'
  thin (1.2.2) bin/thin:6
  /opt/local/bin/thin:19:in `load'
  /opt/local/bin/thin:19

Ответы [ 6 ]

23 голосов
/ 27 октября 2009

При включенном protect_from_forgery Rails требует токен аутентификации для любых не-GET запросов. Rails автоматически включает токен аутентификации в формы, созданные с помощью помощников форм, или ссылки, созданные с помощью помощников AJAX, поэтому в обычных случаях вам не придется об этом думать.

Если вы не используете встроенную форму Rails или помощников AJAX (возможно, вы делаете ненавязчивый JS или используете инфраструктуру JS MVC), вам придется самостоятельно установить токен на стороне клиента и отправить его вместе с вашими данными при отправке запроса POST. Вы бы поместили такую ​​строку в <head> вашего макета:

<%= javascript_tag "window._token = '#{form_authenticity_token}'" %>

Тогда ваша функция AJAX отправит токен с другими вашими данными (пример с jQuery):

$.post(url, {
    id: theId,
    authenticity_token: window._token
});
12 голосов
/ 20 сентября 2016

Это то же самое, что и ответ @ user1756254 , но в Rails 5 вам нужно использовать немного другой синтаксис:

protect_from_forgery unless: -> { request.format.json? }

Источник: http://api.rubyonrails.org/v5.0/classes/ActionController/RequestForgeryProtection.html

12 голосов
/ 22 октября 2009

У меня была похожая ситуация, и проблема была в том, что я не отправлял через правильные заголовки типов контента - я запрашивал text/json, и я должен был запрашивать application/json.

Я использовал curl следующее для проверки моего приложения (при необходимости измените):

curl -H "Content-Type: application/json" -d '{"person": {"last_name": "Lambie","first_name": "Matthew"}}' -X POST http://localhost:3000/people.json -i

Или вы можете сохранить JSON в локальный файл и вызвать curl следующим образом:

curl -H "Content-Type: application/json" -v -d @person.json -X POST http://localhost:3000/people.json -i

Когда я изменил заголовки типов контента вправо application/json все мои проблемы исчезли, и мне больше не нужно было отключать защиту от подделки.

4 голосов
/ 06 февраля 2014

Другой способ - избегать verify_authenticity_token с помощью skip_before_filter в вашем приложении Rails:

skip_before_action :verify_authenticity_token, only: [:action1, :action2]

Это позволит curl делать свою работу.

2 голосов
/ 19 декабря 2014

Чтобы добавить к ответу Фернандо, если ваш контроллер отвечает и на json, и на html, вы можете использовать:

      skip_before_filter :verify_authenticity_token, if: :json_request?
2 голосов
/ 28 октября 2009

Добавляя ответ к andymism, вы можете использовать его, чтобы применить включение TOKEN по умолчанию в каждый запрос POST:

$(document).ajaxSend(function(event, request, settings) {
    if ( settings.type == 'POST' ||  settings.type == 'post') {
        settings.data = (settings.data ? settings.data + "&" : "")
            + "authenticity_token=" + encodeURIComponent( window._token );
    }
});
...