Я написал SPA, написанный на Angular, и использую аутентификацию на основе токенов Azure AD с ресурсами (такими как API), которые защищены токенами на предъявителя. Это позволяет SPA получать токены обновления из Azure и постоянно оставаться в системе, насколько я знаю, всегда.

Я использую библиотеку ADAL JavaScript для Angular, чтобы сделать это:

https://github.com/AzureAD/azure-activedirectory-library-for-js

Теперь существует требование ограничить сессию пользователей заранее определенным количеством времени, скажем, 15 часов.

Я написал хороший небольшой сервис, который сохраняет куки при входе в систему, каждый запрос проверяет дату в куки и превышает ли они максимальный лимит сеанса. Это прекрасно работает, если пользователь постоянно использует приложение или закрывает браузер - но если они оставляют свой браузер открытым, токен просто обновится в фоновом режиме и останется в системе.

Сейчас я пытаюсь решить эту проблему, используя решение без вывода сообщений. То есть я бы хотел, чтобы пользователь был вынужден перейти на страницу безопасного входа после окончания сеанса.

Похоже, что это будет распространенный сценарий, но я не могу понять, как этого добиться, поскольку 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();
            }
        }
    }
1
nocarrier 24 Апр 2017 в 23:55

2 ответа

Лучший ответ

Я написал хороший небольшой сервис, который сохраняет куки при входе в систему, каждый запрос проверяет дату в куки и превышает ли они максимальный лимит сеанса. Это прекрасно работает, если пользователь постоянно использует приложение или закрывает браузер - но если они оставляют свой браузер открытым, токен просто обновится в фоновом режиме и останется в системе.

Исходя из описания, кажется, что код проверки даты выполняется после перехватчика HTTP-запроса adal-angular.js.

Если это возможно, вам нужно реализовать эту функцию перед перехватчиком библиотеки ADAL.

Если это невозможно, вы можете изменить бизнес-логику, чтобы проверить, не истек ли сеанс приложения, до получения токена. Для этого нам нужно изменить исходный код библиотеки аутентификации Active Directory (ADAL) для JavaScript.

Например, вы можете изменить перехватчик HTTP-запроса adal-angular.js , используемый для вставки кода, чтобы проверить, находится ли ваше приложение в сеансе. Вот код перехватчика для вашей справки:

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);
            }
        }
    };
}]);
2
Fei Xue - MSFT 25 Апр 2017 в 02:35

Посмотрите на метод adalAuthenticationService logOut(). Я думаю, проблема в том, что вы использовали logout() неправильно. Обратите внимание на верхний регистр o в методе logout().

1
Quality Catalyst 20 Окт 2017 в 03:41
43597566