2017-03-10 4 views
0

각도가없는 adal.js 라이브러리를 사용하는 데 문제가 있습니다. (나는 Vue.js. 사용하고 있습니다)Adal.js가 localstorage에 소품을 설정하지 않았습니다.

내가 (정확한 값은 무죄를 보호하기 위해 변경되었습니다) 다음과 같은 옵션으로 구성되어 인증 컨텍스트 인스턴스가 내 로그인에

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

을 페이지에서 authContext.login()을 호출하면 AAD에 처음 로그인하는 https://login.microsoftonline.com/으로 리디렉션됩니다. 로그인에 성공하면 URL의 id_token 매개 변수와 함께 위의 구성된 URI에서 응용 프로그램으로 다시 연결됩니다. 그러나 토큰 또는 기타 특성은 라이브러리에 의해 로컬 저장 영역에 저장되지 않고 구성의 일부 특성 만 저장됩니다. 로그인에 성공한

, 나는 로컬 스토리지에있어 모두는, 지금까지의 AAD에 관한 한, 나는 성공적으로 인증 한 그래서

{ 
    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: "" 
} 

이지만, 라이브러리 자체는 어떤 사용자의 아무 개념이없는 것 같다 어떤 토큰이 그들과 연관되어 있는지, 토큰이 만료되었을 때 등 어떤 방법으로 진행할지에 대한 조언이 가장 감사 할 것입니다. 미리 읽어 주셔서 감사합니다.

답변

0

JavaScript (ADAL JS) 용 Active Directory 인증 라이브러리는 단일 페이지 응용 프로그램에서 인증을 처리하는 데 Azure AD를 사용할 수 있도록 도와줍니다. 이 라이브러리는 AngularJS와 함께 작동하도록 최적화되어 있습니다.

코딩하지 않으면 캐시에 토큰을 저장하지 않습니다. 상대 코드는 adal-angular.js에서 확인할 수 있습니다. 참조 용 코드는 다음과 같습니다.

saveTokenFromHash 메서드는 토큰을 캐시에 저장하며이 기능은 페이지가 각도 앱으로 다시 리디렉션 된 후에 실행됩니다.

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

그리고이 기능은 아래와 같이 this.$get에서 호출됩니다 여기

// 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); 
    } 
... 

그리고는 참조 용 캐시에 토큰을 절약 할 수있는 샘플 코드입니다 :

<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

답장을 보내 주셔서 감사합니다. 'handleWindowCallback'가 이미 둘 다 호출 할 때'getRequestInfo'와'saveTokenFromHash'를 수동으로 호출해야하는 이유는 무엇입니까? –

+0

'handleWindowCallBack'을 직접 호출 했는가? 경우 예. 그것은 또한 작동해야합니다. 개발중인 정확한 코드를 공유 하시겠습니까? –