表单提交后更新 CSRF

Renew CSRF after form submit

我想实现我在该图像中显示的功能。用户将单击编辑按钮并激活页面中单个字段的表单。

使用Ajax我会更新一个模型,成功后会再次恢复显示。这里的问题是CSRF_TOKEN。用户更新第一个字段后,无论是哪个字段,第二次编辑都会 return 错误 500 令牌不匹配消息。

我尝试了很多不同的方法,包括我在这里看到的最后一种方法:

$.ajaxSetup( {
  beforeSend: function( xhr, settings ){
    function getCookie( name ){
      var cookieValue = null;

      if( document.cookie && document.cookie != '' ){
        var cookies = document.cookie.split( ';' );
        for( var i = 0; i < cookies.length; i++ ){
          var cookie = jQuery.trim( cookies[ i ] );
          // Does this cookie string begin with the name we want?
          if( cookie.substring( 0, name.length + 1 ) == ( name + '=' ) ){
            cookieValue = decodeURIComponent( cookie.substring( name.length + 1 ) );
            break;
          }
        }
      }
      return cookieValue;
    }
    if( !( /^http:.*/.test( settings.url ) || /^https:.*/.test( settings.url ) ) ){
      // Only send the token to relative URLs i.e. locally.
      xhr.setRequestHeader( "X-CSRFToken", getCookie( 'csrftoken' ) );
    }
  }
} );

但我仍然在第二次提交时收到错误。我知道我需要做的就是在我的元 <meta name="csrf-token" content="{{ csrf_token() }}"> 中更新令牌的值,但我 运行 不知道如何去做,我真的想在不刷新页面的情况下保留这个功能。

也许可以从控制器发送新的 CSRF,它是 return 的结果,并在 ajax 请求的成功阶段使用类似 $( 'meta[name="csrf-token"]' ).val( response.csrf ); 的内容?

       $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content')
            }
        });

我的回答包括修改至少两个文件,执行 ajax 的模板和接收表单请求的控制器。从页面中的表单接收操作的所有方法都应该 return 更新的 csrf 令牌和包含 csrf 值的所有字段(如果有的话)也应该在 ajax 执行后更新。

首先,blade 模板将对文档中的所有表单使用通用的 csrf 标记,为此,我将元 csrf-token 添加到我的 header 部分,如下所示通常:

<meta name="csrf-token" content="{{ csrf_token() }}">

现在,ajax 脚本必须在模板中的任何表单执行后插入令牌并更新元数据:

$( 'body' ).on( 'submit', '.form', function( event ){
  event.preventDefault();
  let fd = new FormData( $( this )[ 0 ] );
  fd.append( '_token', $( 'meta[name="csrf-token"]' ).attr( 'content' ) )

  $.ajax( {
    url : '{{ route( 'service.update', [ 'service' => $service ] ) }}',
    method : 'post',
    data : fd,
    contentType: false,
    processData: false,
    success: function( response ){
      $( 'meta[name="csrf-token"]' ).attr( 'content', response.token );
      //Do all the other things that need to be done...
    },
    error: function( xhr, status, error ){
      console.log( error );
    }
  } );
} );

现在,我做的第一件事是创建一个包含表单内容的 FormData object,并将元数据中的 csrf 值添加到字段集 (fd.append( '_token', $( 'meta[name="csrf-token"]' ).attr( 'content' ) ))。

执行完成后,我的 javascript 将收到一个带有 .token 值的响应变量,其中包含新的 csrf-token 值,所以我用新的元值更新旧的元值: $( 'meta[name="csrf-token"]' ).attr( 'content', response.token );.

现在,对于控制器端,我需要做的就是将令牌值添加到 jSon,在我的例子中它是一个数组,所以我只需要像这样添加它:

$response[ 'token' ] = $request->session()->token();
return $response;

现在表格可以正常工作了,谢谢