为什么在登出时调用的$ state.go转换有时仅在注销时转换?... angular ... ui-router

时间:2016-08-13 10:24:16

标签: angularjs session angular-ui-router

我有一个使用会话维护状态和身份验证的应用。除了一件事,一切都很好。当用户注销并且会话被销毁时,$ state.go转换并不总是触发。它大部分时间都会转换回登录页面,但不是所有时间都会转换回登录页面。我使用抽象状态来解析用户是登录还是注销,并将用户分别限制在仪表板或登录页面。是否有某种顺序,我必须做任何人可能会看到的事情或其他任何可能导致这种行为的事情?

我的$ state config:

app.config(function ($stateProvider, $urlRouterProvider,$locationProvider) {

    $urlRouterProvider.otherwise("/dashboard");
    $locationProvider.html5Mode(true);

    $stateProvider.state('no_session',{
        abstract:true,
        template: "<ui-view/>",
        resolve: {
            authenticated:function($rootScope,$q, Session){
                var deferred = $q.defer();
                var session = Session.getSession();
                if (session) {
                    $rootScope.authenticated = true;
                }
                if (!$rootScope.authenticated){
                    deferred.resolve({authenticated:false});
                } else {
                    deffered.reject({authenticated:true});
                }
            }
        }
    });

    $stateProvider.state('no_session.login', {
    url: '/',
        templateUrl: 'app/views/auth/login.html',
        controller:'AuthCtrl'
    });

    $stateProvider.state('session', {
        abstract: true,
        template: "<ui-view/>",
        resolve: {
            authenticated:function($rootScope,$q,Session){
                var deferred = $q.defer();
                var session = Session.getSession();
                if (session) {
                    $rootScope.authenticated = true;
                }
                if ($rootScope.authenticated===true){
                    deferred.resolve({authenticated:true});
                } else {
                    deffered.reject({authenticated:false});
                }
            }
        }
    });

    $stateProvider.state('session.dashboard', {
        url:'/dashboard',
        templateUrl:'app/views/auth/dashboard.html'
    });

});

app.run (function( $rootScope, $state){
    $rootScope.$on("$stateChangeStart", function (event, current, previous, eventObj) {

    });

    $rootScope.$on("$stateChangeError", function (event, current, previous, eventObj) {
        if (!$rootScope.authenticated) {
            $state.go('no_session.login');      
        } else {
            $state.go('session.dashboard');
        }
    });
});

我的身份验证控制器(Data.get(&#39;退出&#39;)返回“成功”以及登录请求):

app.controller('AuthCtrl', ['$window','$state','$scope','$rootScope', 'Data', function ($window,$state,$scope, $rootScope,  Data) {
    $scope.login = function () {
        var user = $scope.user;
        Data.post('login', {
            user:user
        }).then(function(results){
            if (results.data.status == 'success') {
                Data.toast(results.data);
                $rootScope.authenticated=true;
                $rootScope.name=results.data.name;          
                $rootScope.user_id=results.data.user_id; 
                $window.sessionStorage["session"] = JSON.stringify({authenticated:true});
                $state.go('session.dashboard');
            } else {
                Data.toast(results.data);
                $scope.user = angular.copy($scope.master);          }
            })
    };

    $scope.logout = function () {
        Data.get('logout').then(function(results){
            $state.go('no_session.login');
            Data.toast(results);
            $rootScope.authenticated=null;
            $rootScope.name=null;
            $rootScope.user_id=null;
            $window.sessionStorage["session"] = null;
        });
    }
}]);

我的会话工厂(用来做更多但是我将大部分代码移到控制器上):

app.factory('Session', ['Data','$rootScope','$q','$window', function(Data, $rootScope,$q,$window){

    var session;

    function init() {
        if ($window.sessionStorage["session"]) {
            session = JSON.parse($window.sessionStorage["session"]);
        }
    }
    init();


    function getSession(){
        return session;
    }

    return {
        getSession: getSession
    }

}]);

实际上现在看一下,这家工厂可能不再做任何事了,可能就是问题所在。它只能从$ state resolves调用,并且可能有一种方法可以在没有工厂的情况下执行此操作。我可能应该将所有$ rootScope内容移动到工厂中以清除$ rootScope,如果我&#39我们在这里学到了什么,从工厂回复了对做出决定的承诺,但它是一个如此小的应用程序,这个会话信息是我在那里存储的唯一东西......我不知道。有什么建议?提前谢谢。

1 个答案:

答案 0 :(得分:0)

我做的第一件事是从Session.getSession()返回一个承诺,并在我的决心中使用了这个承诺。同样根据@Mikko Viitala的建议,我从我的决议中返回了一个承诺,并在运行块中访问了被拒绝的延迟:$stateChangeError。我从auth控制器的登录和注销功能中取出所有会话处理程序的东西,并将它们放回会话工厂,将从登录请求返回的会话数据发送到工厂并将其存储在本地存储中。首次实例化工厂时,它会检查本地存储中的会话数据,并分别设置会话和已验证的变量。 $rootScope中仍存储的唯一内容是$rootScope.authenticated。我用它来显示和隐藏应用程序中所有视图的内容。最好的部分是登录和注销状态更改现在像魅力一样工作!哦,如果你想知道烤面包机做了什么,不知道什么,请查看https://github.com/jirikavi/AngularJS-Toaster - 这是一个很棒的模块,可以向用户显示精美的动画通知。

状态配置:

$stateProvider.state('no_session',{
    abstract:true,
    template: "<ui-view/>",
    resolve: {
        authenticated:function($q,Session){
            var deferred = $q.defer();
            var session = Session.getSession();
            session.then(function(user){
                if (!user.user_id){
                    deferred.resolve();
                } else {
                    deferred.reject({'authenticated':true})
                }
            })
            return deferred.promise;
        }
    }
});

$stateProvider.state('no_session.login', {
    url: '/',
    templateUrl: 'app/views/auth/login.html',
    controller:'AuthCtrl'
});

$stateProvider.state('session', {
    abstract: true,
    template: "<ui-view/>",
    resolve: {
        authenticated:function($q,Session){
            var deferred = $q.defer();
            var session = Session.getSession();
            session.then(function(user){
                if (user.user_id){
                    deferred.resolve();
                } else {
                    deferred.reject({'authenticated':false})
                }
            })
            return deferred.promise;
        }
    }
});

$stateProvider.state('session.dashboard', {
    url:'/dashboard',
    templateUrl:'app/views/auth/dashboard.html'
});

然后在运行区:

$rootScope.$on("$stateChangeError", function (event, toState, toParams, fromState, fromParams, error) {
    if (error.authenticated == true){
        $state.go('session.dashboard');
    } else {
        $state.go('no_session.login');
    }
});

然后是AuthCtrl:

app.controller('AuthCtrl', ['$http','$window','$state','$scope','Session','toaster', function ($http,$window,$state,$scope,Session,toaster) {

$scope.login = function () {
    var user = $scope.user;
    $http.post('api/login',user).then(function(result){
        if (result.data.status == 'error'){
            toaster.pop(result.data.status, "", result.data.message, 4000, 'trustedHtml');
        } else {
            Session.setSession(result.data.user);
            toaster.pop(result.data.status, "", result.data.message, 4000, 'trustedHtml');
            $state.go('session.dashboard');
        }
    });
};

$scope.logout = function () {
    $http.get('api/logout').then(function(result){
        Session.killSession();
        toaster.pop(result.data.status, "", result.data.message, 4000, 'trustedHtml');
        $state.go('no_session.login');
    });
}

}]);

会话工厂:

app.factory('Session', ['$q','$localStorage','$rootScope',function($q,$localStorage,$rootScope){

var session = {};

function init() {
    if ($localStorage.session){
        session = $localStorage.session;
        $rootScope.authenticated = true;
    }
}
init();

function setSession(user){
    session = user;
    $rootScope.authenticated = true;
    $localStorage.session = user;

}

function killSession(){
    session = {};
    $rootScope.authenticated = false;
    delete $localStorage.session;
}

function getSession(){
    var deferred = $q.defer();
    deferred.resolve(session);
    return deferred.promise;
} 

return {
    getSession: getSession,
    setSession: setSession,
    killSession: killSession
}

}]);