2017-03-10 4 views
0

Ich habe ein Problem mit der Adal.js-Bibliothek ohne Angular. (Ich verwende Vue.js.)Adal.js nicht setzen Requisiten in localStorage

Ich habe eine Authentifizierungskontext Instanz, die mit den folgenden Optionen aufgebaut ist (genaue Werte geändert wurden, um die Unschuldigen zu schützen):

let config = { 
    tenant: '<tenant id>', 
    clientId: '<client id>', 
    redirectUri: 'http://myapplication.com/index.html', 
    // popUp: true, 
    cacheLocation: 'localStorage' 
} 

Auf meinem Login Seite, rufe ich authContext.login() auf, die mich zuerst zu https://login.microsoftonline.com/ umleitet, wo ich mich in AAD anmelde. Nach erfolgreicher Anmeldung führt mich eine weitere Weiterleitung zurück zu meiner Anwendung, zu dem oben konfigurierten URI, zusammen mit einem Parameter id_token in der URL. Von der Bibliothek im lokalen Speicher werden jedoch keine Token oder andere Eigenschaften gespeichert, nur einige Eigenschaften, die das Ergebnis der Konfiguration sind.

Bei erfolgreicher Anmeldung Alles, was ich in localstorage haben, ist

{ 
    adal.access.token.key: "", 
    adal.error: "" 
    adal.error.description: "" 
    adal.expiration.key: "0" 
    adal.idtoken: "" 
    adal.login.error: "" 
    adal.login.request: "http://myapplication.com/#/login" 
    adal.nonce.idtoken: "<a non-empty string>" 
    adal.session.state: "" 
    adal.state.login: "<a non-empty string>" 
    adal.token.keys: "" 
    adal.username: "" 
} 

Also, so weit wie AAD betrifft, so habe ich erfolgreich authentifiziert, aber die Bibliothek scheint selbst keine Ahnung von dem, was Benutzer zu haben eingeloggt ist, welche Token ihnen zugeordnet sind, wann das Token abläuft, etc. Vielen Dank im Voraus für das Lesen.

Antwort

0

Die Active Directory-Authentifizierungsbibliothek für JavaScript (ADAL JS) unterstützt Sie bei der Verwendung von Azure AD für die Authentifizierung in Ihren Einzelseitenanwendungen. Diese Bibliothek ist für die Zusammenarbeit mit AngularJS optimiert.

Die Tokens werden nicht im Cache gespeichert, es sei denn, wir codieren sie. Sie können den relativen Code von adal-angular.js überprüfen. Hier ist ein Stück Code für Ihre Referenz:

Die saveTokenFromHash Methode wird auch die Token in den Cache speichern und diese Funktion wird nach der Seite Redirect zurück zur Angular App ausgeführt werden.

adal.js:

AuthenticationContext.prototype.saveTokenFromHash = function (requestInfo) { 
    this._logstatus('State status:' + requestInfo.stateMatch); 
    this._saveItem(this.CONSTANTS.STORAGE.ERROR, ''); 
    this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, ''); 

    // Record error 
    if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ERROR_DESCRIPTION)) { 
     this._logstatus('Error :' + requestInfo.parameters.error); 
     this._logstatus('Error description:' + requestInfo.parameters[this.CONSTANTS.ERROR_DESCRIPTION]); 
     this._saveItem(this.CONSTANTS.STORAGE.FAILED_RENEW, requestInfo.parameters[this.CONSTANTS.ERROR_DESCRIPTION]); 
     this._saveItem(this.CONSTANTS.STORAGE.ERROR, requestInfo.parameters.error); 
     this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, requestInfo.parameters[this.CONSTANTS.ERROR_DESCRIPTION]); 

     if (requestInfo.requestType === this.REQUEST_TYPE.LOGIN) { 
      this._loginInProgress = false; 
      this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, requestInfo.parameters.errorDescription); 
     } else { 
      this._renewActive = false; 
     } 
    } else { 

     // It must verify the state from redirect 
     if (requestInfo.stateMatch) { 
      // record tokens to storage if exists 
      this._logstatus('State is right'); 
      if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.SESSION_STATE)) { 
       this._saveItem(this.CONSTANTS.STORAGE.SESSION_STATE, requestInfo.parameters[this.CONSTANTS.SESSION_STATE]); 
      } 

      var keys, resource; 

      if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ACCESS_TOKEN)) { 
       this._logstatus('Fragment has access token'); 
       // default resource 
       this._renewActive = false; 
       resource = this.config.loginResource; 
       if (!this._hasResource(resource)) { 
        keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS) || ''; 
        this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, keys + resource + this.CONSTANTS.RESOURCE_DELIMETER); 
       } 

       if (requestInfo.requestType === this.REQUEST_TYPE.RENEW_TOKEN) { 
        resource = this._getResourceFromState(requestInfo.stateResponse); 
       } 

       // save token with related resource 
       this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource, requestInfo.parameters[this.CONSTANTS.ACCESS_TOKEN]); 
       this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, this._expiresIn(requestInfo.parameters[this.CONSTANTS.EXPIRES_IN])); 
      } 

      if (requestInfo.parameters.hasOwnProperty(this.CONSTANTS.ID_TOKEN)) { 
       this._loginInProgress = false; 
       this._user = this._createUser(requestInfo.parameters[this.CONSTANTS.ID_TOKEN]); 
       if (this._user && this._user.profile) { 
        if (this._user.profile.nonce !== this._getItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN)) { 
         this._user = null; 
         this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, 'Nonce is not same as ' + this._idTokenNonce); 
        } else { 
         this._saveItem(this.CONSTANTS.STORAGE.IDTOKEN, requestInfo.parameters[this.CONSTANTS.ID_TOKEN]); 

         // Save idtoken as access token for app itself 
         resource = this.config.clientId; 
         if (!this._hasResource(resource)) { 
          keys = this._getItem(this.CONSTANTS.STORAGE.TOKEN_KEYS) || ''; 
          this._saveItem(this.CONSTANTS.STORAGE.TOKEN_KEYS, keys + resource + this.CONSTANTS.RESOURCE_DELIMETER); 
         } 
         this._saveItem(this.CONSTANTS.STORAGE.ACCESS_TOKEN_KEY + resource, requestInfo.parameters[this.CONSTANTS.ID_TOKEN]); 
         this._saveItem(this.CONSTANTS.STORAGE.EXPIRATION_KEY + resource, this._user.profile.exp); 
        } 
       } 
      } 
     } else { 
      this._saveItem(this.CONSTANTS.STORAGE.ERROR, 'Invalid_state'); 
      this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, 'Invalid_state'); 
      if (requestInfo.requestType === this.REQUEST_TYPE.LOGIN) { 
       this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, 'State is not same as ' + requestInfo.stateResponse); 
      } 
     } 
    } 
}; 

Und diese Funktion wird in this.$get wie unten genannt werden:

// special function that exposes methods in Angular controller 
// $rootScope, $window, $q, $location, $timeout are injected by Angular 
this.$get = ['$rootScope', '$window', '$q', '$location', '$timeout', function ($rootScope, $window, $q, $location, $timeout) { 

    var locationChangeHandler = function() { 
     var hash = $window.location.hash; 

     if (_adal.isCallback(hash)) { 
      // callback can come from login or iframe request 

      var requestInfo = _adal.getRequestInfo(hash); 
      _adal.saveTokenFromHash(requestInfo); 
      $window.location.hash = ''; 

      if (requestInfo.requestType !== _adal.REQUEST_TYPE.LOGIN) { 
       _adal.callback = $window.parent.AuthenticationContext().callback; 
      } 

      // Return to callback if it is send from iframe 
      if (requestInfo.stateMatch) { 
       if (typeof _adal.callback === 'function') { 
        // Call within the same context without full page redirect keeps the callback 
        if (requestInfo.requestType === _adal.REQUEST_TYPE.RENEW_TOKEN) { 
         // Idtoken or Accestoken can be renewed 
         if (requestInfo.parameters['access_token']) { 
          _adal.callback(_adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['access_token']); 
          return; 
         } else if (requestInfo.parameters['id_token']) { 
          _adal.callback(_adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION), requestInfo.parameters['id_token']); 
          return; 
         } 
        } 
       } else { 
        // normal full login redirect happened on the page 
        updateDataFromCache(_adal.config.loginResource); 
        if (_oauthData.userName) { 
         //IDtoken is added as token for the app 
         $timeout(function() { 
          updateDataFromCache(_adal.config.loginResource); 
          $rootScope.userInfo = _oauthData; 
          // redirect to login requested page 
          var loginStartPage = _adal._getItem(_adal.CONSTANTS.STORAGE.START_PAGE); 
          if (loginStartPage) { 
           $location.path(loginStartPage); 
          } 
         }, 1); 
         $rootScope.$broadcast('adal:loginSuccess'); 
        } else { 
         $rootScope.$broadcast('adal:loginFailure', _adal._getItem(_adal.CONSTANTS.STORAGE.ERROR_DESCRIPTION)); 
        } 
       } 
      } 
     } else { 
      // No callback. App resumes after closing or moving to new page. 
      // Check token and username    
      updateDataFromCache(_adal.config.loginResource); 
      if (!_adal._renewActive && !_oauthData.isAuthenticated && _oauthData.userName) { 
       if (!_adal._getItem(_adal.CONSTANTS.STORAGE.FAILED_RENEW)) { 
        // Idtoken is expired or not present 
        _adal.acquireToken(_adal.config.loginResource, function (error, tokenOut) { 
         if (error) { 
          $rootScope.$broadcast('adal:loginFailure', 'auto renew failure'); 
         } else { 
          if (tokenOut) { 
           _oauthData.isAuthenticated = true; 
          } 
         } 
        }); 
       } 
      } 
     } 

     $timeout(function() { 
      updateDataFromCache(_adal.config.loginResource); 
      $rootScope.userInfo = _oauthData; 
     }, 1); 
    } 
... 

Und hier ist ein Beispielcode, der die Token in den Cache für Ihre Referenz retten könnte:

<html> 
<head> 
<script src="https://unpkg.com/vue"></script> 
<script src="node_modules\adal-angular\lib\adal.js"> </script> 
<script src="config.js"> </script> 
</head> 

<body> 
<div> 
    <button onclick="login()" >Login</button> 
</div> 
    <script> 

var authContext=new AuthenticationContext(config); 
function login(){ 
authContext.login(); 

} 

function init(configOptions){ 
    if (configOptions) { 
        // redirect and logout_redirect are set to current location by default 
        var existingHash = window.location.hash; 
        var pathDefault = window.location.href; 
        if (existingHash) { 
         pathDefault = pathDefault.replace(existingHash, ''); 
        } 
        configOptions.redirectUri = configOptions.redirectUri || pathDefault; 
        configOptions.postLogoutRedirectUri = configOptions.postLogoutRedirectUri || pathDefault; 


        // create instance with given config     
       } else { 
        throw new Error('You must set configOptions, when calling init'); 
       } 

       // loginresource is used to set authenticated status 
       updateDataFromCache(authContext.config.loginResource); 

} 

var _oauthData = { isAuthenticated: false, userName: '', loginError: '', profile: '' }; 
    var updateDataFromCache = function (resource) { 
       // only cache lookup here to not interrupt with events 
       var token = authContext.getCachedToken(resource); 
       _oauthData.isAuthenticated = token !== null && token.length > 0; 
       var user = authContext.getCachedUser() || { userName: '' }; 
       _oauthData.userName = user.userName; 
       _oauthData.profile = user.profile; 
       _oauthData.loginError = authContext.getLoginError(); 
      }; 

init(config); 

function saveTokenFromHash(){ 
    var hash = window.location.hash; 
    var requestInfo = authContext.getRequestInfo(hash); 
     if (authContext.isCallback(hash)) { 
         // callback can come from login or iframe request 

         var requestInfo = authContext.getRequestInfo(hash); 
         authContext.saveTokenFromHash(requestInfo); 
         window.location.hash = ''; 

         if (requestInfo.requestType !== authContext.REQUEST_TYPE.LOGIN) { 
          authContext.callback = window.parent.AuthenticationContext().callback; 
         }     
        } 
} 

saveTokenFromHash(); 
    </script> 

</body> 
</html> 
+0

Vielen Dank für Ihre Antwort. Warum ist es notwendig, 'getRequestInfo' und' saveTokenFromHash' manuell aufzurufen, wenn 'handleWindowCallback' bereits beide für mich aufruft? –

+0

Meinst du, dass du den 'handleWindowCallBack' selbst nennst? Falls ja. Es sollte auch funktionieren. Würde es Ihnen etwas ausmachen, den genauen Code zu teilen, den Sie entwickelt haben? –