尽管 Laravel 中的令牌正确,Ajax 调用仍返回 419 错误

Posted

技术标签:

【中文标题】尽管 Laravel 中的令牌正确,Ajax 调用仍返回 419 错误【英文标题】:Ajax calls return 419 error despite correct token in Laravel 【发布时间】:2018-08-31 19:49:39 【问题描述】:

我的 Laravel 应用程序中有一堆使用 Ajax 发出的 POST 请求。

一个典型的请求如下所示:

$.ajax(
    url: '/path/to/method',
    data: 'id': id,
    type: 'POST',
    datatype: 'JSON',
    success: function (response) 
        //handle data
    ,
    error: function (response) 
        //handle error
    
);

我设置了 CSRF 令牌,并且大部分时间一切正常:

jQuery(document).ready(function()
$.ajaxSetup(
    headers: 
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    
);
);

但是,在长时间中断后(例如,计算机长时间休眠),所有 Ajax 调用都会返回 419 错误,就好像没有设置令牌一样。重新加载页面后,一切恢复正常。这是在本地服务器上。

我该如何解决这个问题?有没有办法在通话前“更新”令牌?每次通话前我必须做$.ajaxSetup 位吗?在页面加载时执行一次还不够?

【问题讨论】:

你可以像this那样处理 @Thamilan 没有比 1) 延长会话寿命和 2) 显示错误更好的方法来处理这个问题?如果用户在一两天后打开他的笔记本电脑,前一种方法并没有真正的帮助,而后一种方法对用户不是很友好。 如果这是由客户端/服务器端的会话到期引起的,那么您应该使用某种计时器机制在前端检查会话到期。当计时器检测到会话到期并且您的会话已到期时,请在提示下注销用户。当用户在会话到期时间之前在网页上执行某些操作时,不要忘记在客户端重置会话(服务器应该是自动的)。 我不认为 csrf 令牌是要走的路。我会改为实现 api 令牌(不是护照)。这是一个很好的起点gistlog.co/JacobBennett/090369fbab0b31130b51 收到 419 后立即触发页面刷新。 【参考方案1】:

这是我的建议:

JS

   //create a function to set header
    function setHeader(data)
        $.ajaxSetup(
            headers: 
               'X-CSRF-TOKEN': data
             
         );
    
   //in first load of the page set the header
    setHeader($('meta[name="csrf-token"]').attr('content'));

   //create function to do the ajax request cos we need to recall it when token is expire
    function runAjax(data)
      $.ajax(
         url: '/path/to/method',
         data: 'id': id,
         type: 'POST',
         datatype: 'JSON',
         success: function (response) 
            //handle data
         ,
         error: function (jqXHR, textStatus, errorThrown) 
             if(jqXHR.status==419)//if you get 419 error which meantoken expired
                refreshToken(function()refresh the token
                    runAjax();//send ajax again
                );
             
         
     );
    

   //token refresh function
    function refreshToken(callback)
          $.get('refresh-csrf').done(function(data)
             setHeader(data);
              callback(true);
           );
    
    //Optional: keep token updated every hour
     setInterval(function()
            refreshToken(function()
                    console.log("Token refreshed!");
                );

            , 3600000); // 1 hour 

路线

//route to get the token
Route::get('refresh-csrf', function()
    return csrf_token();
);

希望这会有所帮助。

【讨论】:

Laravel 的默认实现是,如果令牌过期,则需要另一个身份验证会话来创建新的会话令牌(即重定向到登录页面)。有什么不对吗?

以上是关于尽管 Laravel 中的令牌正确,Ajax 调用仍返回 419 错误的主要内容,如果未能解决你的问题,请参考以下文章

Laravel中的令牌不匹配ajax

禁用 Ajax 调用的 CSRF 保护 - 它有多糟糕?

laravel 5中多个异步ajax请求中的CSRF令牌不匹配错误?

如何使用 ajax 在 LARAVEL 中获取新的 CSRF 令牌

本地主机上 laravel 5.3 中 ajax 发布请求中的 CSRF 令牌不匹配异常

.append 上的 Laravel ajax“无效或意外令牌”