JWT刷新后运行AJAX请求

时间:2017-08-31 16:45:04

标签: javascript jquery ajax token jwt

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

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

    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语句中对其进行编码。

1 个答案:

答案 0 :(得分:0)

您需要向checkTokenExp()添加回调,以便在API令牌刷新后完成API调用。

现在发生了什么:

  1. 您准备致电api/random
  2. beforeSend执行checkTokenExp()
  3. 如果令牌已过期,则会要求另一个异步
  4. 实际调用api/random,可能是在服务器使用新令牌回复第3步之前
  5. 查看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();
        }
    }
    
相关问题