2009-08-07 71 views
14

出於某種原因,當使用json或xml向我的應用程序發送發佈請求時,我得到一個InvalidAuthenticityToken。我的理解是,軌道應該只需要一個真實性標記爲html或js請求,因此我不應該遇到這個錯誤。我迄今爲止發現的唯一解決方案是禁用protect_from_forgery,以便通過API訪問任何操作,但由於顯而易見的原因,這並不理想。思考?rails - 針對json/xml請求的InvalidAuthenticityToken

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 

當我將內容類型標題更改爲application/json所有我的麻煩消失了,我不再需要禁用僞造保護。

+0

這並不能真正爲Web應用程序的工作,雖然。瀏覽器無法運行卷曲。 =( – NullVoxPopuli 2012-02-29 23:14:55

+3

問題是我用curl調試了這個問題,發現發送正確的Content-Type頭是很重要的。 – mlambie 2012-03-07 03:35:08

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}})' – 2016-11-22 18:29:10

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 2012-02-29 23:14:18

4

另一種方法是避免verify_authenticity_token使用skip_before_filter您Rails App:

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

這會讓curl去完成它的工作。

2

要添加到阿隆索的回答,如果你的控制器既響應JSON和HTML,您可以使用:

 skip_before_filter :verify_authenticity_token, if: :json_request? 
+1

這不是安全風險嗎? – 2016-11-22 17:53:12

10

這是一樣的@user1756254's answer但在Rails的5,你需要使用多一點不同的語法:

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

來源:http://api.rubyonrails.org/v5.0/classes/ActionController/RequestForgeryProtection.html

+3

這不是安全風險嗎? – 2016-11-22 17:53:31

+1

@WylliamJudd否,僅爲JSON禁用它並不構成安全風險,因爲僞造保護目標是保護從其他網站提交的HTML表單 – edwardmp 2016-11-22 19:11:28

+2

當官方文檔顯示:_'if您正在構建一個API,你應該改變ApplicationController中的僞造保護方法(默認情況下::exception)'_,那麼它足夠安全 – 2017-08-30 23:36:12

相關問題