2009-08-07 5 views
14

По какой-то причине я получаю InvalidAuthenticityToken при отправке почтовых запросов в мое приложение при использовании json или xml. Я понимаю, что рельсы должны требовать токен аутентификации только для запросов html или js, и поэтому я не должен сталкиваться с этой ошибкой. Единственное решение, которое я нашел до сих пор, - это отключить защиту_from_forgery для любых действий, которые я хотел бы получить через API, но это не идеально по понятным причинам. Мысли?rails - InvalidAuthenticityToken для запросов json/xml

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 

ответ

12

У меня была похожая ситуация, и проблема в том, что я не отправлял через правильного содержания типа - я просил 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 

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

+0

это действительно не работает для веб-приложений, хотя. Браузеры не могут запускать завиток. = ( – NullVoxPopuli

+3

Дело было в том, что я отлаживал проблему с помощью curl и обнаружил, что важно отправить правильный заголовок Content-Type. – mlambie

19

С включенным 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 
}); 
+1

Optimate должен принять этот ответ. Кстати, если вы используете '$ .ajax', вам нужно поместите токен аутентификации в поле данных следующим образом: '$ .ajax ({data: {authenticity_token: window._token}})' –

2

Добавление до ответ andymism в вы можете использовать это, чтобы применить включение по умолчанию токен каждого запроса 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); 
    } 
}); 
+1

Точка api_key заключается в том, чтобы избежать наличия auth_token – NullVoxPopuli

4

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

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

Это позволит завитка выполнять свою работу.

2

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

 skip_before_filter :verify_authenticity_token, if: :json_request? 
+1

Это не риск для безопасности? –

10

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

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

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

+3

Является ли это не угрозой безопасности? –

+1

@WylliamJudd нет, отключив его только для JSON, не представляет угрозы безопасности, поскольку цель защиты от подделки - защищать HTML-формы, представленные с других сайтов. – edwardmp

+2

Когда в официальной документации говорится: «Если вы строите API вы должны изменить метод защиты подделок в ApplicationController (по умолчанию:: exception) '_, тогда он достаточно безопасен –

Смежные вопросы