jQuery将CSRF令牌添加到所有$ .post()请求的数据中

我正在开发一个Laravel 5应用程序,该应用程序默认为所有POST请求启用CSRF保护。 我喜欢这个增加的安全性所以我正在尝试使用它。

在进行简单的$.post()请求时,我收到了'Illuminate\Session\TokenMismatchException'错误,因为POST数据中缺少所需的表单输入_token 。 以下是有问题的$ .post请求的示例:

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

我将CSRF令牌存储为标题中的元字段,并可以使用以下方法轻松访问它:

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

是否可以将此附加到所有传出$.post()请求的json数据? 我尝试使用标题,但Laravel似乎没有认出它们 –

 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); } }); 

你的$.ajaxPrefilter方法很好。 但是,您不需要添加标题; 您只需要向data字符串添加属性。

数据作为$.post的第二个参数提供,然后在预filter访问data选项之前格式化为查询字符串( id=foo&bar=baz&... )。 因此,您需要将自己的字段添加到查询字符串:

 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); } }); 

这会将id=userID转换为id=userID&_token=csrf_token

来自Laravel文档:

例如,您可以将令牌存储在“meta”标记中:

创建元标记后,您可以指示像jQuery这样的库将标记添加到所有请求标头。 这为基于AJAX的应用程序提供了简单,方便的CSRF保护:

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

例如,您可以像下面那样提出要求。

将此元标记添加到您的视图中:

  

这是一个示例脚本,您可以与Laravel进行通信(当您单击id =“some-id”的元素时发送请求,您可以在id =“result”的元素中看到响应):

  

一般来说,我同意Kornel建议的概念,除了一件事。

是的,Laravel的文档建议使用$.ajaxSetup ,但不建议这样$.ajaxSetup ,因为此方法会影响所有后续的ajax请求。 为每个请求设置ajax设置更为正确。 虽然你可以重新设置东西:

使用任何函数的所有后续Ajax调用都将使用新设置,除非被单个调用覆盖,直到下一次调用$ .ajaxSetup()

如果使用$.ajax() ,则使用data属性或headers更方便。 Laravel允许CSRF令牌作为请求参数或标头。

首先,在视图中添加以下元标记

  

然后以任何一种方式发出ajax请求:

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

要么

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

关于CSRF的Django文档提供了一个带有ajaxSetup的漂亮代码片段,用于自动将适当的头添加到所有重要的请求类型:

 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); } } }); 

我认为上述解决方案可能效果不佳。 当你这样做时:

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

你会得到像“undefined_token = xxx”这样的数据

例如,当您使用上述解决方案进行laravel的删除时,您必须像这样检查:

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

有一个更容易的方法来执行此操作,您可以在发送之前序列化数据

 

具有名称attr的所有内容都将被放入查询并提交