jQuery añade token CSRF a todos los datos de las solicitudes $ .post ()

Estoy trabajando en una aplicación Laravel 5 que tiene habilitada la protección CSRF por defecto para todas las solicitudes POST. Me gusta esta seguridad adicional, así que estoy tratando de trabajar con ella.

Al realizar una solicitud $.post() simple recibí un error 'Illuminate\Session\TokenMismatchException' porque la entrada de formulario requerida _token faltaba en los datos POST. Aquí hay un ejemplo de una solicitud de $ .post en cuestión:

 var userID = $("#userID").val(); $.post('/admin/users/delete-user', {id:userID}, function() { // User deleted }); 

Tengo mi token CSRF almacenado como un meta campo en mi encabezado y puedo acceder fácilmente usando:

 var csrf_token = $('meta[name="csrf-token"]').attr('content'); 

¿Es posible agregar esto a los datos json en todas las solicitudes salientes $.post() ? Intenté usar encabezados, pero Laravel no pareció reconocerlos.

 var csrf_token = $('meta[name="csrf-token"]').attr('content'); alert(csrf_token); $.ajaxPrefilter(function(options, originalOptions, jqXHR){ if (options['type'].toLowerCase() === "post") { jqXHR.setRequestHeader('X-CSRFToken', csrf_token); } }); 

Su enfoque $.ajaxPrefilter es bueno. No es necesario agregar un encabezado, sin embargo; simplemente necesita agregar una propiedad a la cadena de data .

Los datos se proporcionan como el segundo argumento para $.post , y luego formateados como una cadena de consulta ( id=foo&bar=baz&... ) antes de que el prefiltro acceda a la opción de data . Por lo tanto, debe agregar su propio campo a la cadena de consulta:

 var csrf_token = $('meta[name="csrf-token"]').attr('content'); $.ajaxPrefilter(function(options, originalOptions, jqXHR){ if (options.type.toLowerCase() === "post") { // initialize `data` to empty string if it does not exist options.data = options.data || ""; // add leading ampersand if `data` is non-empty options.data += options.data?"&":""; // add _token entry options.data += "_token=" + encodeURIComponent(csrf_token); } }); 

Esto convertirá id=userID en id=userID&_token=csrf_token .

De la documentación de Laravel:

Podría, por ejemplo, almacenar el token en una etiqueta “meta”:

Una vez que haya creado la metaetiqueta, puede instruir a una biblioteca como jQuery para que agregue el token a todos los encabezados de solicitud. Esto proporciona una protección CSRF simple y conveniente para sus aplicaciones basadas en AJAX:

$ .ajaxSetup ({headers: {‘X-CSRF-TOKEN’: $ (‘meta [nombre = “csrf-token”]’). attr (‘contenido’)}});

Entonces, por ejemplo, puede hacer la solicitud como a continuación.

Agregue esta metaetiqueta a su vista:

  

Y este es un script de ejemplo que puede comunicar con Laravel (envía una solicitud cuando hace clic en un elemento con id = “some-id” y puede ver la respuesta en un elemento con id = “resultado”):

  

En general, estoy de acuerdo con el concepto que Kornel sugirió excepto una cosa.

Sí, los consejos de Laravel docs para usar $.ajaxSetup , pero no se recomienda ya que este método afecta todas las solicitudes ajax subsiguientes. Es más correcto establecer las configuraciones de Ajax para cada solicitud. Aunque puedes volver a configurar cosas:

Todas las llamadas Ajax subsiguientes que usen cualquier función usarán la nueva configuración, a menos que sean anuladas por las llamadas individuales, hasta la próxima invocación de $ .ajaxSetup ()

Si usa $.ajax() , es más conveniente utilizar propiedades de data o headers . Laravel permite CSRF-token como un parámetro de solicitud o un encabezado.

Primero, agregue la siguiente metaetiqueta en la vista

  

Y luego haz una solicitud de AJAX de cualquier forma:

 $.ajax({ url: "/your/url", method: "POST", data: { a: 'something', b: 'something else', _token: $('meta[name="csrf-token"]').attr('content') }, datatype: "json" }); 

O

 $.ajax({ url: "/your/url", method: "POST", data: { a: 'something', b: 'something else', }, headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } datatype: "json" }); 

La documentación de Django en CSRF brinda un buen fragmento de código con ajaxSetup para agregar automáticamente el encabezado apropiado a todos los tipos de solicitud donde sea importante:

 function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); 

Creo que la solución anterior podría no funcionar tan bien. Cuando tu lo hagas:

 var x; x + "" // "undefined" + empty string coerces value to string 

Obtendrás datos como “undefined_token = xxx”

Cuando utilizas la solución anterior para eliminar laravel, por ejemplo, tienes que marcar de esta manera:

 if (typeof options.data === "undefined") options.data = ""; else options.data += "&"; options.data = "_token=" + csrf_token; 

hay un método mucho más fácil para hacer esto, puede serializar los datos de esa manera antes de enviar

 

todo con un nombre attr se incluirá en una consulta y se enviará