Adal.js没有在localStorage中设置道具

时间:2017-03-10 21:17:02

标签: vue.js adal adal.js

我在使用没有Angular的adal.js库时遇到问题。 (我正在使用Vue.js。)

我有一个身份验证上下文实例,它使用以下选项构建(确切的值已被更改以保护无辜者):

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

在我的登录页面上,我调用了authContext.login(),它首先将我重定向到https://login.microsoftonline.com/,然后我登录到AAD。成功登录后,另一个重定向将我带回我的应用程序,在我上面配置的URI,以及URL中的id_token参数。但是,库中没有令牌或其他属性存储在本地存储中,只有一些属性是配置的结果。

成功登录后,我在localStorage中的所有内容都是

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

因此,就AAD而言,我已经成功通过身份验证,但是库本身似乎没有关于用户登录的内容,与令牌关联的令牌,令牌何时到期等等的概念。任何建议关于如何进行将是非常感谢。提前感谢您的阅读。

1 个答案:

答案 0 :(得分:0)

  

用于JavaScript的Active Directory身份验证库(ADAL JS)可帮助您使用Azure AD在单页应用程序中处理身份验证。该库经过优化,可与AngularJS一起使用。

除非我们对代码进行编码,否则它不会将令牌保存到缓存中。您可以查看 adal-angular.js 中的相关代码。以下是一段代码供您参考:

saveTokenFromHash方法还会将令牌保存到缓存中,此功能将在页面重定向回Angular应用程序后执行。

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>