rails – json / xml请求的InvalidAuthenticityToken

出于某种原因,在使用json或xml时向我的应用程序发出请求时,我收到了InvalidAuthenticityToken。 我的理解是rails应该只为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 

启用protect_from_forgery ,Rails需要任何非GET请求的真实性令牌。 Rails会自动在使用表单助手创建的表单中包含真实性令牌或使用AJAX助手创建的链接 – 因此在正常情况下,您不必考虑它。

如果您没有使用内置的Rails表单或AJAX助手(也许您正在使用不引人注目的JS或使用JS MVC框架),您必须自己在客户端设置令牌并将其与您一起发送提交POST请求时的数据。 你可以在你的布局的中添加这样的一行:

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

然后你的AJAX函数将使用你的其他数据发布令牌(例如使用jQuery):

 $.post(url, { id: theId, authenticity_token: window._token }); 

我有类似的情况,问题是我没有通过正确的内容类型标头发送 – 我正在请求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我的所有麻烦都消失了,我不再需要禁用伪造保护。

这与@ user1756254的答案相同,但在Rails 5中,您需要使用更多不同的语法:

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

资料来源: http : //api.rubyonrails.org/v5.0/classes/ActionController/RequestForgeryProtection.html

另一种方法是在Rails应用程序中使用skip_before_filter来避免verify_authenticity_token:

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

这将让curl完成它的工作。

添加到andymism的答案,您可以使用它来在每个POST请求中应用默认的TOKEN:

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

要添加到Fernando的答案,如果您的控制器同时响应json和html,您可以使用:

  skip_before_filter :verify_authenticity_token, if: :json_request?