【问题标题】:AngularJs SPA logoutAngularJs SPA 注销
【发布时间】:2016-06-26 07:06:54
【问题描述】:

我在这里AngularJs logout action 发布了更复杂的问题。但我还有另一个方面要看,我认为它应该是分开的问题。

我有带有身份验证的 Angualr SPA。使用不记名 JWT 令牌实现的身份验证。我使用ng-route 提出不同的观点。让我们想象一下,一个视图(使用/protected 路由、protecetedControllerprotectedDataService)包含受保护的资源,而另一个视图(使用/unprotected 路由、unprotecetedControllerunprotectedDataService)包含不受保护的资源。控制器示例代码:

(function () {
    'use strict';

    angular
        .module('protectedCtrl',[])
        .controller('protectedController', ['$location','protectedDataService', function ($location, protectedDataService) {
            var vm = this;
            vm.title = 'protectedController';
            protectedDataService.getData().then(function (res) {
                vm.values = res.data;
            }, function (err) {
                console.log(err);
            });
        }]);
})();

不受保护的控制器:

(function () {
    'use strict';

    angular
        .module('unprotectedCtrl',[])
        .controller('unprotectedController', ['$location','unprotectedDataService', function ($location, unprotectedDataService) {
            var vm = this;
            vm.title = 'unprotectedController';
            unprotectedDataService.getData().then(function (res) {
                vm.values = res.data;
            }, function (err) {
                console.log(err);
            });
        }]);
})();

如果未登录的用户访问受保护的资源(/protected 路径),他将被重定向到登录页面。但是让我们想象一下,该登录用户按下注销按钮(现在我只是从浏览器本地存储中删除我的令牌信息并重新加载页面)。如果用户在/protected 页面上,他应该被重定向到登录页面。如果他在/unprotected 页面上,则不会发生任何事情。我该如何实施?如何确定ng-view 中哪个页面处于活动状态(需要或不需要身份验证)并决定重定向?

【问题讨论】:

    标签: javascript angularjs authentication single-page-application logout


    【解决方案1】:

    您可以使用$routeChangeStart 事件来捕捉路由的变化和帮助函数来决定是否重定向到登录页面。

    在您的 Angular 应用程序的 run 块中,为不需要身份验证的路由定义一个变量,以及一个检查用户前往的路由是否在此列表中的函数。

    angular
      .module('awesomeApp')
      .run(function (/* inject dependencies */) {
        // other code
    
        // Define a list of routes that follow a specific rule. This example
        // can be extended to provide access based on user permissions by
        // defining other variables that will list routes that require the
        // user to have specific permissions to access those routes.
        var routesThatDoNotRequireAuthentication = ['/unprotected'];
    
        // Check if current location is contained in the list of given routes.
        // Note: the check here can be made using different criteria. For
        // this example I check whether the route contains one of the
        // available routes, but you can check for starting position, or other criteria.
        function rootIsPresent ( route, availableRoutes ) {
          var routeFound = false;
          for ( var i = 0, l = availableRoutes.length; i < l; i++ ) {
            routeFound = routeFound || route.indexOf(availableRoutes[i]) > -1;
          }
          return routeFound;
        }
    
        // And now, when the $routeChangeStart event is fired, check whether
        // its safe to let the user change the route.
        $rootScope.$on('$routeChangeStart', function () {
          // Get the authentication status of a user
          var isAuthenticated = authenticationService.isAuthenticated();
          var newRoute = $location.url();
    
          // If the route requires authentication and the user is not 
          // authenticated, then redirect to login page.
          if ( !rootIsPresent(newRoute, routesThatDoNotRequireAuthentication) && !isAuthenticated ) {
            $location.path('/login');
          }
        });
    });
    

    更新

    似乎我误解了这个问题,并认为您的所有路线都以/protected/unprotected 为前缀(如果您考虑一下,在大多数情况下确实不是那么聪明)。

    在这种情况下,您可以在$routeProvider 中定义路由时设置一个附加属性:

    $routeProvider
      .when('/awesomePath', {
        templateUrl: 'awesome-template.html',
        controller: 'AwesomeController',
        controllerAs: 'vm',
        requireAuth: true  // add the property that defines a route as protected or unprotected
      })
    

    现在,在您的 $routeChangeStart 处理程序函数中,您检查用户要前往的路由是否受到保护:

    $rootScope.$on('$routeChangeStart', function () {
          // Get the authentication status of a user
          var isAuthenticated = authenticationService.isAuthenticated();
          var newRoute = $location.url();
    
          // In a controller, $route object has a 'current' property that
          // holds route defined route properties, but here the 'current'
          // property is null, so we need to get the $route object we 
          // need by using the $location.url()
          if ( $route.routes[$location.url()].requireAuth && !isAuthenticated ) {
            $location.path('/login');
          }
        });
    

    因此您无需在任何地方硬编码您的路线。

    【讨论】:

    • 谢谢。但根据您的建议,我应该在 routesThatDoNotRequireAuthentication 数组中注册所有路线。这是肮脏的把戏。)也许我可以在定义它们时为所有不受保护的路由留下一些标记?在app.config() 或其他地方?或者以某种方式标记控制器?
    • @Stalso 似乎我已经从字面上理解了,并认为您的路线以受保护/不受保护为前缀。我用更优雅的解决方案更新了我的答案。
    • 谢谢。这是最优雅的解决方案。
    猜你喜欢
    • 2022-07-02
    • 2017-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    • 2018-11-25
    • 2013-08-22
    相关资源
    最近更新 更多