24

何らかの理由で、json または xml を使用しているときにアプリケーションにポスト リクエストを行うと、InvalidAuthenticityToken が発生します。私の理解では、Rails は html または js リクエストに対してのみ認証トークンを要求する必要があるため、このエラーが発生することはありません。これまでに見つけた唯一の解決策は、API を介してアクセスしたいすべてのアクションに対して protect_from_forgery を無効にすることですが、これは明らかな理由から理想的ではありません。考え?

    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
4

7 に答える 7

28

有効に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
});
于 2009-10-26T22:59:21.223 に答える
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すべての問題が解消され、偽造保護を無効にする必要がなくなりました。

于 2009-10-22T16:54:15.567 に答える
12

これは@ user1756254 の回答と同じですが、Rails 5 ではもう少し異なる構文を使用する必要があります。

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

ソース: http://api.rubyonrails.org/v5.0/classes/ActionController/RequestForgeryProtection.html

于 2016-09-19T21:27:12.740 に答える
3

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 );
    }
});
于 2009-10-28T00:38:50.030 に答える
1

フェルナンドの答えに追加するには、コントローラーがjsonとhtmlの両方に応答する場合、次を使用できます。

      skip_before_filter :verify_authenticity_token, if: :json_request?
于 2014-12-19T19:46:43.960 に答える