2016-08-13 43 views
0

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

我的$状态配置:

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( '注销')返回 '成功',以及登录请求):

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 
    } 

}]); 

实际上现在看它,这个工厂p可以自由地再也没有做任何事情,并且可能是问题所在。它只是从$ state中调用来解析,而且可能有一种方法可以在没有factory的情况下执行。我可能应该将所有$ rootScope的东西移到工厂中,以清除$ rootScope中的内容,如果我在此处了解到任何内容回复了对工厂解决方案的承诺,但它是一个如此小的应用程序,而且这个会话信息是我在那里存储的唯一的东西。我不知道。有什么建议么?提前致谢。

+0

TL; DR;在你的决心,不应该'返回deferred.promise;'? –

+1

是...感谢您的帮助,我想出了下面的解决方案 – OGZCoder

回答

0

我做的第一件事是从Session.getSession()返回一个承诺,并用我的决心承诺。也正如@Mikko Viitala所建议的那样,我从我的决议中回复了一个承诺,并访问了运行块中被拒绝的延期:$stateChangeError。我将所有会话处理程序的东西从auth控制器的登录和注销功能中取出,并将它们放回到Session工厂中,将从登录请求返回的会话数据发送到工厂,并将其存储在本地存储中。当工厂首次实例化时,它会检查本地存储中的会话数据,并分别设置会话和认证变量。仍存储在$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 
} 

}]);