ruby-on-rails - rails - actioncontroller:: invalidauthenticitytoken
rails-InvalidAuthenticityToken para solicitudes json/xml (6)
Por alguna razón, obtengo un InvalidAuthenticityToken al realizar solicitudes de publicación en mi aplicación cuando uso json o xml. Tengo entendido que los rieles deben requerir un token de autenticidad solo para las 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?
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 obtengo en los registros cuando paso 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
Agregando a la respuesta de andymism, puede usar esto para aplicar la inclusión predeterminada de TOKEN en cada 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 );
}
});
Con protect_from_forgery
habilitado, Rails requiere un token de autenticidad para cualquier solicitud que no sea GET. Rails incluirá automáticamente el token de autenticidad en los formularios creados con los ayudantes de formularios o los 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 JS no intrusivo o utilizando un marco JS MVC), deberá establecer el token en el lado del cliente y enviarlo junto con su Datos al enviar una solicitud POST. Deberías poner una línea como esta en el <head>
de tu diseño:
<%= javascript_tag "window._token = ''#{form_authenticity_token}''" %>
Luego, su función AJAX publicaría el token con sus otros datos (ejemplo con jQuery):
$.post(url, {
id: theId,
authenticity_token: window._token
});
Esto es lo mismo que la respuesta de @ user1756254 pero en Rails 5 necesitas usar un poco más de sintaxis diferente:
protect_from_forgery unless: -> { request.format.json? }
Fuente: http://api.rubyonrails.org/v5.0/classes/ActionController/RequestForgeryProtection.html
Otra forma es evitar verificar_autenticidad_título usando skip_before_filter en su aplicación Rails:
skip_before_action :verify_authenticity_token, only: [:action1, :action2]
Esto permitirá a Curl hacer su trabajo.
Para agregar a la respuesta de Fernando, si su controlador responde tanto a json como a html, puede usar:
skip_before_filter :verify_authenticity_token, if: :json_request?
Tuve una situación similar y el problema fue que no estaba enviando a través de los encabezados del tipo de contenido correcto: estaba solicitando text/json
y debería haber estado solicitando application/json
.
Utilicé el siguiente curl
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
como esto:
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 application/json
correcta application/json
todos mis problemas desaparecieron y ya no tuve que deshabilitar la protección de falsificación.