如果刷新(JWT)令牌未经授权(401响应),AngularJS重定向到登录
Posted
技术标签:
【中文标题】如果刷新(JWT)令牌未经授权(401响应),AngularJS重定向到登录【英文标题】:AngularJS redirect to login if Refresh (JWT) token gets unauthorized (401 response) 【发布时间】:2019-07-12 05:35:52 【问题描述】:如果刷新 (jwt) 令牌未经授权(在第一个令牌过期后),我将面临将用户重定向到登录页面的问题。代币未授权有两种情况;
第一个:当 jwt 令牌基于 401 响应过期时,将调用新的刷新服务以通过 $http-interceptors (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);
;
]);
在 service 和 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;
根据上面的代码,请指导我做错了什么,或者登录/实现可能有问题。无论哪种情况,请帮助我。谢谢
【问题讨论】:
大家可以在这里添加任何可以帮助我解决问题的内容!那真的很有帮助 【参考方案1】:我设法通过以下代码行简单地解决了这个问题;
配置 (app.js)
// Cache this request
var deferred = $q.defer();
if(!cachedRequest)
// Cache request for renewing Access Token and wait for Promise
cachedRequest = AuthorizationTokenService.refreshAccessToken();
else
// this is where it checks for request token expiry
do_logout();
【讨论】:
以上是关于如果刷新(JWT)令牌未经授权(401响应),AngularJS重定向到登录的主要内容,如果未能解决你的问题,请参考以下文章