2009-08-07 34 views
14

Vì một lý do nào đó, tôi nhận được một InvalidAuthenticityToken khi gửi yêu cầu đăng bài đến ứng dụng của tôi khi sử dụng json hoặc xml. Sự hiểu biết của tôi là các đường ray nên yêu cầu mã thông báo xác thực chỉ cho các yêu cầu html hoặc js và do đó tôi không nên gặp phải lỗi này. Giải pháp duy nhất tôi đã tìm thấy cho đến nay là vô hiệu hóa protect_from_forgery cho bất kỳ hành động nào tôi muốn truy cập thông qua API, nhưng điều này không lý tưởng cho các lý do rõ ràng. Suy nghĩ?đường ray - InvalidAuthenticityToken cho yêu cầu 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 

và đây là những gì tôi nhận được trong các bản ghi bất cứ khi nào tôi vượt qua một yêu cầu đến hành động:

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 

Trả lời

12

tôi đã có một tình huống tương tự và vấn đề là tôi đã không được gửi thông qua các nội dung đúng loại tiêu đề - Tôi đã yêu cầu text/json và tôi đã yêu cầu application/json.

tôi đã sử dụng curl sau đây để kiểm tra ứng dụng của tôi (sửa đổi nếu cần thiết):

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

Hoặc bạn có thể lưu JSON vào một tập tin địa phương và gọi curl như thế này:

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

Khi Tôi đã thay đổi tiêu đề loại nội dung sang bên phải application/json tất cả các rắc rối của tôi đã biến mất và tôi không còn cần phải tắt tính năng bảo vệ giả mạo nữa.

+0

này không thực sự làm việc cho các ứng dụng web mặc dù. Trình duyệt không thể chạy curl. = ( – NullVoxPopuli

+3

Vấn đề là tôi đã sửa lỗi vấn đề với curl và thấy rằng điều quan trọng là phải gửi tiêu đề Kiểu nội dung phù hợp. – mlambie

19

Khi bật tính năng protect_from_forgery, Rails yêu cầu mã thông báo xác thực cho mọi yêu cầu không được GET. Rails sẽ tự động bao gồm mã thông báo xác thực trong các biểu mẫu được tạo bằng trình trợ giúp biểu mẫu hoặc liên kết được tạo bằng trình trợ giúp AJAX - vì vậy trong các trường hợp thông thường, bạn sẽ không phải suy nghĩ về nó.

Nếu bạn không sử dụng biểu mẫu Rails tích hợp hoặc trình trợ giúp AJAX (có thể bạn đang làm JS không rõ ràng hoặc sử dụng khung công tác JS MVC), bạn sẽ phải tự đặt mã thông báo ở phía máy khách và gửi nó cùng với dữ liệu của bạn khi gửi yêu cầu POST. Bạn muốn đặt một dòng như thế này trong <head> bố cục của bạn:

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

Sau đó, chức năng AJAX của bạn sẽ gửi các mã thông báo với các dữ liệu khác của bạn (ví dụ với jQuery):

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

Optimate nên chấp nhận câu trả lời này. Bằng cách này, nếu bạn sử dụng '$ .ajax' bạn cần đặt mã thông báo xác thực vào trường dữ liệu như sau: '$ .ajax ({data: {authenticity_token: window._token}})' –

2

Thêm lên đến câu trả lời andymism của bạn có thể sử dụng để áp dụng sự bao gồm mặc định của tOKEN trong mọi yêu cầu 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

Điểm của api_key là tránh để có auth_token – NullVoxPopuli

4

Một cách khác là để tránh verify_authenticity_token sử dụng skip_before_filter tại của bạn Rails App:

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

Điều này sẽ cho phép cuộn tròn để thực hiện công việc của mình.

2

Để thêm vào câu trả lời Fernando, nếu điều khiển của bạn phản ứng với cả json và html, bạn có thể sử dụng:

 skip_before_filter :verify_authenticity_token, if: :json_request? 
+1

Đây có phải là rủi ro bảo mật không? –

10

Đây là giống như @user1756254's answer nhưng trong Rails 5 bạn cần sử dụng một chút cú pháp khác nhau hơn :

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

Nguồn: http://api.rubyonrails.org/v5.0/classes/ActionController/RequestForgeryProtection.html

+3

Đây có phải là rủi ro bảo mật không? –

+1

@WylliamJudd không, vô hiệu hóa nó chỉ với JSON không gây nguy cơ bảo mật như mục tiêu bảo vệ giả mạo là bảo vệ các biểu mẫu HTML được gửi từ các trang khác – edwardmp

+2

Khi tài liệu chính thức cho biết: _'if bạn đang xây dựng một API, bạn nên thay đổi phương thức bảo vệ giả mạo trong ApplicationController (theo mặc định:: exception) '_, sau đó nó đủ an toàn –

Các vấn đề liên quan