2017-04-24 4 views
2

J'ai écrit un SPA écrit en Angular, et j'utilise l'authentification par jeton Azure AD, avec des ressources (comme des API) qui sont sécurisées par des jetons de support. Cela permet au SPA de récupérer des jetons de renouvellement depuis Azure et de rester connecté en permanence, pour autant que je sache, pour toujours.Déconnexion forcée ADAL JS dans SPA

J'utilise la bibliothèque JavaScript pour ADAL angulaire de le faire:

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

Maintenant, il est nécessaire de limiter la session d'utilisateurs à quantité prédéterminée de temps, disons 15 heures.

J'ai écrit un joli petit service qui stocke un cookie lors de la connexion, chaque demande vérifie la date dans le cookie et si elles ont dépassé leur limite de session maximale. Cela fonctionne bien si l'utilisateur utilise continuellement l'application, ou ferme le navigateur - mais s'il laisse son navigateur ouvert, le jeton sera simplement renouvelé en arrière-plan et ils resteront connectés.

J'essaie maintenant de résoudre ce problème en utilisant une solution de déconnexion silencieuse. Ce qui signifie, je voudrais que l'utilisateur soit forcé à la page de connexion sécurisée une fois que leur session a expiré.

Cela semble être un scénario courant, mais je n'arrive pas à comprendre comment y parvenir, car ADAL utilise un iFrame en arrière-plan. J'ai pensé à utiliser une minuterie/intervalle, mais cela semble hokey.

Juste pour info J'utilise adalAuthenticationService.logout() par mon exemple de code ci-dessous. J'ai également essayé d'effacer le cache de session, ce qui fonctionne - mais ADAL rafraîchira silencieusement le jeton. J'ai également essayé de placer l'emplacement de redirectUri à une page non authentifiée, mais quand même, il redirigera seulement là si l'utilisateur prend l'action. Si le navigateur reste simplement ouvert, le jeton se réinitialisera tout seul.

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(); 
      } 
     } 
    } 

Répondre

3

j'ai écrit un service peu agréable qui stocke un cookie lors de la connexion, chaque demande, il vérifie la date dans le cookie et si elles ont dépassé leur limite maximale de session. Cela fonctionne bien si l'utilisateur utilise sans cesse l'application, ou ferme le navigateur -. Mais s'ils quittent leur navigateur ouvert, le jeton renouvellera simplement en arrière-plan et ils rester connecté

Sur la base de la description, il semble que le code vérifie que la date est exécutée après l'intercepteur de requête HTTP de adal-angular.js.

Si cela est possible, vous devez implémenter cette fonction avant l'intercepteur de la bibliothèque ADAL.

Si cela est impossible, vous pouvez modifier la logique métier en pour vérifier si la session de l'application n'a pas expiré avant d'acquérir le jeton. Pour cela, nous devons modifier le code source de la bibliothèque ADAL (Active Directory Authentication Library) pour JavaScript.

Par exemple, vous pouvez modifier l'intercepteur de demande HTTP de adal-angular.js utilisé pour insérer le code pour vérifier si votre application est dans la session. Voici le code d'intercepteurs pour votre référence:

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

Regardez la méthode de adalAuthenticationServicelogOut(). Je pense que le problème est que vous avez utilisé logout() de manière incorrecte. Veuillez noter les majuscules de o dans la méthode logout().

+0

Ceci ne fournit pas de réponse à la question. Une fois que vous avez suffisamment [réputation] (https://stackoverflow.com/help/whats-reputation) vous pourrez [commenter n'importe quel article] (https://stackoverflow.com/help/privileges/comment); Au lieu de cela, [fournissez des réponses qui ne nécessitent pas de précisions de la part du demandeur] (https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- je-fais-à la place). - [À revoir] (/ review/low-quality-posts/17680085) –

+0

Oui !. Merci pour la note. J'ai changé ma réponse selon la règle. –