Возникает проблема с перенаправлением пользователя на страницу входа, если токен обновления (jwt) становится неавторизованным (после истечения срока действия первого токена).Существует 2 сценария отмены авторизации токенов:
1-й: Когда срок действия токена jwt истекает на основании ответа 401, вызывается новая служба обновления для генерации нового токена через $ http-перехватчики (config).
2-й: когда токен обновления также получает неавторизованный (401) ответ, это когда пользователь должен перенаправить на страницу входа.
Я могу отправить токен обновления по первому сценарию и он работает нормально, как и ожидалось, но я не могу перенаправить пользователя на страницу входа, если токен обновления также получает неавторизованный (401) ответ.
Вот мой код:
authInterceptor.service.js
angular.module('someApp').factory('AuthorizationTokenService', AuthorizationTokenService);
AuthorizationTokenService.$inject = ['$q', '$injector', '$cookies'];
function AuthorizationTokenService($q, $injector, $cookies) {
// Local storage for token
var tokenVM = {
accessToken: null
};
// Subscribed listeners which will get notified when new Access Token is available
var subscribers = [];
// Promise for getting new Access Token from backend
var deferedRefreshAccessToken = null;
var service = {
getLocalAccessToken: getLocalAccessToken,
refreshAccessToken: refreshAccessToken,
isAccessTokenExpired: isAccessTokenExpired,
subscribe: subscribe
};
return service;
////////////////////////////////////
// Get the new Access Token from backend
function refreshAccessToken() {
// If already waiting for the Promise, return it.
if( deferedRefreshAccessToken ) {
return deferedRefreshAccessToken.promise
} else {
deferedRefreshAccessToken = $q.defer();
// Get $http service with $injector to avoid circular dependency
var http = $injector.get('$http');
http({
method: 'POST',
url: 'api_url',
params: {
grant_type: 'refresh',
id_token: $cookies.get('access_token')
}
})
.then(function mySucces(response) {
var data = response.data;
if( data ){
// Save new Access Token
$cookies.put('access_token', data.access_token);
if( $cookies.get('access_token') ) {
// Resolve Promise
deferedRefreshAccessToken.resolve(data.access_token);
// Notify all subscribers
notifySubscribersNewAccessToken(data.access_token);
deferedRefreshAccessToken = null;
}
}
}, function myError(error) {
deferedRefreshAccessToken.reject(error);
deferedRefreshAccessToken = null;
});
return deferedRefreshAccessToken.promise;
}
}
function getLocalAccessToken() {
// get accesstoken from storage - $cookies
if ( $cookies.get('access_token') ) {
var access_token = $cookies.get('access_token')
return access_token;
}
}
function isAccessTokenExpired() {
// Check if expiresAt is older then current Date
}
function saveToken(accessToken) {
// get accesstoken from storage - $cookies
var access_token = $cookies.put('access_token');
console.log('access_token ' + access_token);
return access_token;
}
// This function will call all listeners (callbacks) and notify them that new access token is available
// This is used to notify the web socket that new access token is available
function notifySubscribersNewAccessToken(accessToken) {
angular.forEach(subscribers, function(subscriber) {
subscriber(accessToken);
});
}
// Subscribe to this service. Be notifyed when access token is renewed
function subscribe(callback) {
subscribers.push(callback);
}
}
И в Config (app.js)
config.$inject = ['$stateProvider', '$urlRouterProvider', '$httpProvider'];
function config($stateProvider, $urlRouterProvider, $httpProvider) {
// Push httpRequestInterceptor
// $httpProvider.interceptors.push('httpRequestInterceptor');
//Intercept all http requests
$httpProvider.interceptors.push(['$injector', '$q', "AuthorizationTokenService", "$cookies", function ($injector, $q, AuthorizationTokenService, $cookies) {
var cachedRequest = null;
return {
request: function (config) {
//If request if for API attach Authorization header with Access Token
if (config.url.indexOf("api") != -1) {
// var accessToken = AuthorizationTokenService.getLocalAccessToken();
console.log('cookie ' + $cookies.get('access_token'));
config.headers.Authorization = 'Bearer ' + $cookies.get('access_token');
}
return config;
},
responseError: function (response) {
switch (response.status) {
// Detect if reponse error is 401 (Unauthorized)
case 401:
// Cache this request
var deferred = $q.defer();
if(!cachedRequest) {
// Cache request for renewing Access Token and wait for Promise
cachedRequest = AuthorizationTokenService.refreshAccessToken();
}
// When Promise is resolved, new Access Token is returend
cachedRequest.then(function(accessToken) {
cachedRequest = null;
if (accessToken) {
// Resend this request when Access Token is renewed
$injector.get("$http")(response.config).then(function(resp) {
// Resolve this request (successfully this time)
deferred.resolve(resp);
},function(resp) {
deferred.reject();
console.log('success: refresh token has expired');
});
} else {
// If any error occurs reject the Promise
console.log('error: refresh token has expired');
deferred.reject();
}
}, function(response) {
// If any error occurs reject the Promise
cachedRequest = null;
deferred.reject();
return;
});
return deferred.promise;
}
// If any error occurs reject the Promise
return $q.reject(response);
}
};
}]);
}
Оба в сервисе & config , я пытался реализовать это перенаправление пользователей на основе двойного 401 (средний токен обновления также истекает и отвечает 401).
Я также пытался с условием множественного потомка 401, но это не сработало.(пример ниже)
responseError: function (response) {
// Detect if reponse error is 401 (Unauthorized)
if (response.status === 401) {
// Cache this request
var deferred = $q.defer();
if(!cachedRequest) {
// Cache request for renewing Access Token and wait for Promise
cachedRequest = AuthorizationTokenService.refreshAccessToken();
}
// When Promise is resolved, new Access Token is returend
cachedRequest.then(function(accessToken) {
cachedRequest = null;
if (response.status === 401) {
console.log('refresh token also expired');
$location.path('/login');
} else {
// Resend this request when Access Token is renewed
$injector.get("$http")(response.config).then(function(resp) {
// Resolve this request (successfully this time)
deferred.resolve(resp);
},function(resp) {
deferred.reject();
console.log('success: refresh token has expired');
});
}
}, function(response) {
// If any error occurs reject the Promise
cachedRequest = null;
deferred.reject();
return;
});
return deferred.promise;
}
}
Основываясь на приведенном выше коде, пожалуйста, сообщите мне, что я делаю неправильно, или, возможно, что-то не так с логином / реализацией.В любом случае, пожалуйста, помогите мне.Спасибо