我编写了一个用Angular编写的SPA,并使用基于Azure AD令牌的身份验证,使用通过承载令牌保护的资源(如API)。这允许SPA从Azure检索续订令牌,并且据我所知,永远保持登录状态。
我正在使用Angular的ADAL JavaScript库来执行此操作:
https://github.com/AzureAD/azure-activedirectory-library-for-js
现在需要将用户会话限制在预定的时间内,比方说15个小时。
我写了一个很好的小服务,它在登录时存储一个cookie,每个请求都会检查cookie中的日期以及它们是否超过了它们的最大会话限制。如果用户不断使用应用程序或关闭浏览器,这样可以正常工作 - 但如果他们让浏览器保持打开状态,则令牌只会在后台续订并保持登录状态。
我现在正试图使用静默注销解决方案来解决这个问题。这意味着,我希望用户在会话过期后被强制进入安全登录页面。
这似乎是一种常见的情况,但我似乎无法弄清楚如何实现它,因为ADAL在后台使用了iFrame。我想过使用一个计时器/间隔,但这看起来很糟糕。
仅供参考我根据以下代码示例使用adalAuthenticationService.logout()。我也尝试清除会话缓存,但是ADAL会静默刷新令牌。我还尝试将redirectUri位置设置为非经过身份验证的页面,但是,如果用户采取操作,它只会重定向到那里。如果浏览器只是保持打开状态,则令牌将自行重置。
var maxTime = 15; // hours allowed in session
// event to fire check; maybe this can be different, and is my problem?
$rootScope.$on('$viewContentLoaded', function () {
$scope.checkLogoutCookie();
});
$scope.logout = function() {
adalAuthenticationService.logout();
};
function setCookie(c) {} // implementation details don't matter....
function getCookie(c) {} // implementation details don't matter....
$scope.checkLogoutCookie = function () {
var lastLogin = getCookie("lastLogin");
var loginDate = new Date();
if (lastLogin === "") { // is empty
setCookie("lastLogin", loginDate, 365);
} else {
var lastDate = new Date(lastLogin);
var hours = Math.abs(lastDate - loginDate) / 36e5;
if (hours > maxTime) {
setCookie("lastLogin", "", 0);
$scope.logout();
}
}
}
答案 0 :(得分:2)
我写了一个很好的小服务,它在登录时存储一个cookie,每个请求都会检查cookie中的日期以及它们是否超过了它们的最大会话限制。如果用户不断使用应用程序或关闭浏览器,这样可以正常工作 - 但如果他们让浏览器保持打开状态,则令牌只会在后台续订并保持登录状态。
根据描述,似乎代码检查日期是在adal-angular.js的HTTP请求拦截器之后执行的。
如果可能,您需要在ADAL库的拦截器之前实现此功能。
如果不可能,您可以将业务逻辑更改为 在获取令牌之前检查应用会话是否未过期。为此,我们需要更改JavaScript的Active Directory身份验证库(ADAL)的源代码。
例如,您可以更改用于插入代码的 adal-angular.js 的HTTP请求拦截器,以检查您的应用是否在会话中。以下是拦截器代码供您参考:
AdalModule.factory('ProtectedResourceInterceptor', ['adalAuthenticationService', '$q', '$rootScope', '$templateCache', function (authService, $q, $rootScope, $templateCache) {
return {
request: function (config) {
if (config) {
config.headers = config.headers || {};
// if the request can be served via templateCache, no need to token
if ($templateCache.get(config.url)) return config;
var resource = authService.getResourceForEndpoint(config.url);
authService.verbose('Url: ' + config.url + ' maps to resource: ' + resource);
if (resource === null) {
return config;
}
//add/modify the code here
var tokenStored = authService.getCachedToken(resource);
if (tokenStored) {
authService.info('Token is available for this url ' + config.url);
// check endpoint mapping if provided
config.headers.Authorization = 'Bearer ' + tokenStored;
return config;
}
else {
// Cancel request if login is starting
if (authService.loginInProgress()) {
if (authService.config.popUp) {
authService.info('Url: ' + config.url + ' will be loaded after login is successful');
var delayedRequest = $q.defer();
$rootScope.$on('adal:loginSuccess', function (event, token) {
if (token) {
authService.info('Login completed, sending request for ' + config.url);
config.headers.Authorization = 'Bearer ' + tokenStored;
delayedRequest.resolve(config);
}
});
return delayedRequest.promise;
}
else {
authService.info('login is in progress.');
config.data = 'login in progress, cancelling the request for ' + config.url;
return $q.reject(config);
}
}
else {
// delayed request to return after iframe completes
var delayedRequest = $q.defer();
authService.acquireToken(resource).then(function (token) {
authService.verbose('Token is available');
config.headers.Authorization = 'Bearer ' + token;
delayedRequest.resolve(config);
}, function (error) {
config.data = error;
delayedRequest.reject(config);
});
return delayedRequest.promise;
}
}
}
},
responseError: function (rejection) {
authService.info('Getting error in the response: ' + JSON.stringify(rejection));
if (rejection) {
if (rejection.status === 401) {
var resource = authService.getResourceForEndpoint(rejection.config.url);
authService.clearCacheForResource(resource);
$rootScope.$broadcast('adal:notAuthorized', rejection, resource);
}
else {
$rootScope.$broadcast('adal:errorResponse', rejection);
}
return $q.reject(rejection);
}
}
};
}]);
答案 1 :(得分:1)
查看adalAuthenticationService
的方法logOut()
。我认为问题在于您错误地使用了logout()
。请注意o
方法中logout()
的大写字母。