javascript - JWT 刷新后运行 AJAX 请求

标签 javascript jquery ajax token jwt

我有一个现有的单页应用程序,我已将其转换为 JWT 而不是 PHP session 。它运行良好,但我试图弄清楚如何在 AJAX 请求之前刷新 JWT(如果需要)。

一点背景:用户登录后,我存储 JWT(10 分钟到期)和刷新 token (2 小时到期)。我想在每次 AJAX 调用 API 之前运行以下函数。该函数检查 JWT 是否过期,如果过期,它将通过刷新 token 检索新的 JWT。显然,在 API 中,我在允许发回数据之前检查 JWT 和刷新 token 的有效性。这部分工作完美。

    function checkTokenExp(){
     var validToken = false;   // DEFAULT TO EXPIRED
     var apiClaims = localStorage.getItem('apiToken').split('.');
     var api = JSON.parse(atob(apiClaims[1]));
     var apiExpiration = new Date(api['exp'] * 1000);
     var now = new Date();
     if (apiExpiration < now) {
       // API TOKEN EXPIRED - CHECK REFRESH TOKEN
       var refreshClaims = localStorage.getItem('refreshToken').split('.');
       var refresh = JSON.parse(atob(refreshClaims[1]));
       var refreshExpiration = new Date(refresh['exp'] * 1000);
       if (refreshExpiration > now) {
         //  REFRESH TOKEN NOT EXPIRED - NEED NEW API TOKEN
         $.ajax({
           type: "GET",
           url: 'api/session/token',
           contentType: 'application/json',
           beforeSend: function (xhr) {
             xhr.setRequestHeader("Authorization", 'Bearer '+localStorage.getItem('refreshToken'));
           }
         }).done(function (data) {
           var data = jQuery.parseJSON(data);
           if (data.status == 'success'){
             localStorage.setItem('apiToken', data.apiToken);
           }
           validToken = true;
         });
       }else{
         //  REFRESH TOKEN EXPIRED - FORCE LOG OUT
         $("#SessionExpiredModal").modal('show');
       }
     }else{
       //  API TOKEN NOT EXPIRED
       validToken = true;
     }
     return validToken;
   }

我遇到麻烦的是下面的代码(以及接下来的所有其他 AJAX 调用)。正如您所看到的,我尝试在此 AJAX 调用之前运行上面的函数并验证我的 JWT(如果无效,则请求并存储新的 JWT),然后使用新的 JWT 运行 AJAX 调用。除了 AJAX 返回 401 未经授权之外,一切正常,因为它仍在发送之前的 JWT(显然已过期)。因此,似乎 AJAX 是在上述函数完成并存储新 JWT 之前发送的。但我知道我的函数运行正确并且 JWT 已更新,因为我第二次单击该按钮时它运行正确并且我从 API 得到了正确的回复。

$('#BtnTest').on('click', function(){
     $.ajax({
      type: "GET",
      url: 'api/random',
      contentType: 'application/json',
      beforeSend: function (xhr) {
        checkTokenExp();  // SHOULD BE SAVING NEW TOKEN
        xhr.setRequestHeader("Authorization", 'Bearer '+ localStorage.getItem('apiToken'));  // SHOULD BE SENDING NEW TOKEN
      }
    }).done(function (response) {
      alert(response);
    })
   });

我希望这是有道理的,并提前感谢您的帮助。另外,有没有一种简单的方法可以让我的函数在每次 ajax 调用之前运行,而不必在每个 AJAX 语句中对其进行编码。

最佳答案

您需要向 checkTokenExp() 添加回调,以便 API token 刷新后即可完成 API 调用。

现在发生了什么:

  1. 您准备调用 api/random
  2. beforeSend 执行 checkTokenExp()
  3. 如果 token 已过期,它会异步请求另一个 token
  4. api/random 的实际调用可能在服务器使用新 token 回复第三步之前进行

看看jQuery's ajaxPrefilter .

你可以尝试这样的事情:

var currentRequests = {};

$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
    // Skip URLs that don't need a token
    if( options.url == 'your api/session/token URL' ) {
        console.log("No ajax prefilter on api/session/token");
        return;
    }

    successCb = function() {
        currentRequests[ options.url ] = jqXHR;
    };
    errorCb = function() {
        console.error("Could not refresh token, aborting Ajax call to " + options.url);
        currentRequests[ options.url ].abort();
    };
    checkTokenExp(successCb, errorCb);
});



function checkTokenExp(successCb, errorCb){
    // ...
    if (refreshExpiration > now) {
        //  REFRESH TOKEN NOT EXPIRED - NEED NEW API TOKEN
        $.ajax({
            type: "GET",
            url: 'api/session/token',
            contentType: 'application/json',
        }).done(function (data) {
            var data = jQuery.parseJSON(data);
            if (data.status == 'success'){
                localStorage.setItem('apiToken', data.apiToken);
                successCb(); // the new token is set, you can make ajax calls
            }
            // TODO: log error here, don't do validToken = true
        }).fail(errorCb(data));
    }else{
        //  REFRESH TOKEN EXPIRED - FORCE LOG OUT
        $("#SessionExpiredModal").modal('show');
    }
    }else{
        //  API TOKEN NOT EXPIRED
        successCb();
    }
}

关于javascript - JWT 刷新后运行 AJAX 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45986487/

相关文章:

Javascript/jquery 无法在其他文件中工作

javascript - 如何在调用下一个 Javascript 函数之前更新浏览器?

javascript - jQuery.ajax 替换 PHP 代码

javascript - 如何通过单击菜单中的 Li 将 HTML 页面加载到 DIV 中?

javascript - 如何正确使用 redux-form 的 debounce?

javascript - 匹配递增的数字

javascript - HTML - 通过单击图像调用 javascript

javascript - 如果我的输入元素位于标签内,jQuery 验证是否有效?

javascript - 当页眉到达顶部时 Div 开始滚动,当底部到达页脚时停止滚动

javascript - 如何在前端截取包含用户上传图片的 div 的屏幕截图?