AngularJS - 防止未经过身份验证的用户访问给定路由

时间:2013-04-09 15:04:34

标签: javascript security angularjs

在我的应用中,当用户登录时,我authService设置了内部标记isAuthenticated。现在,在每次路由更改时,我都会将监听器附加到$routeChangeStart事件,该事件会检查authService.isAuthenticated()。如果没有,它应该重定向到登录路由。

问题是当用户刷新页面时(所有authService设置都丢失了)并且它再次返回登录状态(同时在服务器上仍然有有效的会话)。这不是我想要的。

我想做的是“阻止”路由更改,直到我获得用户身份验证的信息(来自authService的即时消息,或者来自服务器,如果authService中没有信息可用authService 1}},例如刷新后)。我在 // returns promise currentUser: function() { if (authService.isAuthenticated()) { return $q.when(authService.loggedUser); } return $http.get('/session').then(function(response) { authService.loggedUser = response.user; return $q.when(authService.loggedUser); }); }

中有这样的功能
    $rootScope.$on("$routeChangeStart", function (event, next, current) {
        if(isRouteRestricted(next)) {
            authService.currentUser().then(null, function() {
                $location.path('/login');
            });
        }
    });

并希望在事件监听器中使用它。

{{1}}

事情是它不能按预期工作。我仍然可以在很短的时间内看到目标路线,然后用户被重定向。我相信这是由于承诺的本质,但如何摆脱这种“眨眼”效应?

2 个答案:

答案 0 :(得分:6)

我会在顶级控制器中执行类似的操作,这将是刷新页面时调用的第一个控制器(为js中的拼写错误道歉,我是一个coffeescript人):

var authCheck = function (event, next, current) {
    if(isRouteRestricted(next)) {
        authService.currentUser().then(null, function() {
            $location.path('/login');
        });
    }
}

authCheck(null, populateNextSomehow).then(function () {
    // all of your controller code, probably in a separate function
});

$rootScope.$on("$routeChangeStart", authCheck);

这将确保在authCheck完成之前无法调用控制器代码。

答案 1 :(得分:4)

为防止用户访问路由,您必须执行以下操作:

首先,设置路线并添加“访问”等属性:allowAnonymous:true或false

// in app.js
var myApp = angular.module('myApp',['ngResource', 'ngCookies', 'ngRoute']);       
myApp.config(function ($httpProvider, $routeProvider) {
   window.routes = {
        '/Login':
           { templateUrl: '/Account/Login',
             controller: 'AccountController',
             access : {allowAnonymous : true}
           },
        '/MembersPage':
           { templateUrl: '/Home/SomePage,
             controller: SomePageController',
             access: {allowAnonymous:false}
           }
         };

        for (var path in window.routes) {
           $routeProvider.when(path, window.routes[path]);
    }
    $routeProvider.otherwise({ redirectTo: '/Login' });
});   

其次,您必须识别经过身份验证的用户:

有几种方法可以做到这一点,但我更喜欢在使用'服务'时使用AngularJS的强大功能。因此,我创建了一个'UserService',我们存储当前用户名和一个值 - 表明是否经过身份验证。

// in UserService.js
myApp.factory('userService', function () {
var user = {
    isLogged: false,
    username: '',       
};

var reset = function() {
    user.isLogged = false;
    user.username = '';
};

return {
    user: user,
    reset : reset
  };
});

最后,捕获路线会更改事件并相应地对待它们:

在我们提供服务后,是时候使用它并实现路由的检查功能。拦截路由更改事件有几种方法,但我们只对那些在用户重定向之前发生的方法感兴趣,因此我们可以检查是否经过身份验证:'$ routeChangeStart','$ locationChangeStart'。在这里,我们可以检查用户将要允许匿名访问的路由以及用户是否已登录。如果失败,我们可以显示错误消息并将用户重定向到登录页面。

// in RootController.js
myApp.controller('RootController',
function ($scope, $route, $routeParams, $location, $rootScope, authenticationService,   
userService, toaster) {
 $scope.user = userService.user;
 $scope.$on('$routeChangeStart', function (e, next, current) {               
     if (next.access != undefined && !next.access.allowAnonymous && !$scope.user.isLogged) {
                $location.path("/Login");                   
            }
        });

        $scope.logout = function () {
            authenticationService.logout()
                .success(function (response) {
                    userService.reset();                       
                    toaster.pop("info", 'You are logged out.', '');
                });
        };

 $rootScope.$on("$locationChangeStart", function (event, next, current) {
  for (var i in window.routes) {
    if (next.indexOf(i) != -1) {
     if (!window.routes[i].access.allowAnonymous && !userService.user.isLogged) {
          toaster.pop("error", 'You are not logged in!', '');
             $location.path("/Login");                                                 
                    }
                }
            }
        });
    });

完整文章在这里:http://net-daylight.blogspot.ro/

希望它有所帮助!