2009-08-07 16 views
14

Por alguna razón, obtengo un InvalidAuthenticityToken al realizar solicitudes a mi aplicación cuando uso json o xml. Según entiendo, los rieles deben requerir un token de autenticidad solo para solicitudes html o js, ​​y por lo tanto no debería encontrar este error. La única solución que he encontrado hasta ahora es deshabilitar protect_from_forgery para cualquier acción a la que me gustaría acceder a través de la API, pero esto no es ideal por razones obvias. ¿Pensamientos?rails - InvalidAuthenticityToken para solicitudes 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 

y esto es lo que me pasa en los registros cada vez que aprobar una solicitud a la acción:

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 

Respuesta

12

tuve una situación similar y el problema era que no estaba enviando a través del contenido correcto escriba encabezados: estaba solicitando text/json y debería haber estado solicitando application/json.

que utilizan curl la siguiente para probar mi aplicación (modificar según sea necesario):

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

o puede guardar el JSON en un archivo local y llamar a curl así:

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

Cuando Cambié los encabezados de tipo de contenido a la derecha application/json todos mis problemas desaparecieron y ya no necesitaba desactivar la protección contra falsificaciones.

+0

esto no funciona muy bien para las aplicaciones web sin embargo. Los navegadores no pueden ejecutar curl. = ( – NullVoxPopuli

+3

El punto fue que depuré el problema con curl y descubrí que era importante enviar el encabezado Content-Type correcto. – mlambie

19

Con protect_from_forgery activado, Rails requiere un token de autenticidad para cualquier solicitud que no sea GET. Rails incluirá automáticamente el token de autenticidad en formularios creados con ayudantes de formularios o enlaces creados con los ayudantes de AJAX, por lo que, en casos normales, no tendrá que pensar en ello.

Si no está utilizando el formulario Rails incorporado o los ayudantes AJAX (tal vez está haciendo un JS discreto o utilizando un marco JS MVC), tendrá que configurar el token usted mismo en el lado del cliente y enviarlo junto con sus datos al enviar una solicitud POST. Que había puesto una línea como esta en el <head> de su diseño:

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

Luego, su función AJAX sería publicar el token con sus otros datos (ejemplo con jQuery):

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

Optimate debería aceptar esta respuesta. Por cierto, si usa '$ .ajax' necesita pon el token de autenticidad en el campo de datos de esta manera: '$ .ajax ({data: {authenticity_token: window._token}})' –

2

que suman la respuesta de andymism se puede usar esto para solicitar la inclusión por defecto de signo en toda solicitud 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

El objetivo de la api_key es evitar tener un auth_token – NullVoxPopuli

4

Otra manera es evitar el uso de verify_authenticity_token skip_before_filter en su Aplicación Rails:

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

Esto permitirá que Curl haga su trabajo.

2

Para añadir a la respuesta de Fernando, si el controlador responde tanto a JSON y HTML, puede utilizar:

 skip_before_filter :verify_authenticity_token, if: :json_request? 
+1

¿No es esto un riesgo de seguridad? –

10

Esto es lo mismo que @user1756254's answer pero en los carriles 5 tiene que utilizar un poco de sintaxis más diferentes :

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

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

+3

¿Esto no es un riesgo para la seguridad? –

+1

@WylliamJudd no, deshabilitarlo solo JSON no supone un riesgo para la seguridad ya que la protección contra falsificaciones es proteger los formularios HTML enviados desde otros sitios – edwardmp

+2

Cuando la documentación oficial dice: _'si está construyendo una API debe cambiar el método de protección contra falsificaciones en ApplicationController (de forma predeterminada:: excepción) '_, entonces es lo suficientemente seguro –

Cuestiones relacionadas