我有一个现有的单页应用程序,我已将其转换为 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 调用。
现在发生了什么:
- 您准备调用
api/random
beforeSend
执行checkTokenExp()
- 如果 token 已过期,它会异步请求另一个 token
- 对
api/random
的实际调用可能在服务器使用新 token 回复第三步之前进行
你可以尝试这样的事情:
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/