【问题标题】:Angular JS authorization - check user role before loading the pageAngular JS 授权 - 在加载页面之前检查用户角色
【发布时间】:2015-02-28 16:30:30
【问题描述】:

我正在用 Angular JS 编写 cms 前端,但我不知道如何处理授权用户在用户首次加载应用程序时查看特定内容。当用户已经登录并且只是从一个页面导航到另一个页面时,我有工作解决方案。我是这样做的:

angular.module("myApp")
.run ($rootScope, AUTH_EVENTS, AuthServ) ->
    $rootScope.$on '$stateChangeStart', (event, next) ->
      if next.data
        authorizedRoles = next.data.authorizedRoles
        unless AuthServ.isAuthorized(authorizedRoles)
          event.preventDefault()
          if AuthServ.isAuthenticated()
            $rootScope.$broadcast(AUTH_EVENTS.notAuthorized)
          else
            $rootScope.$broadcast(AUTH_EVENTS.notAuthenticated)  

当用户更改路由时,会触发 AuthServ.isAuthorized(authorizedRoles)。

当用户登录时,我从服务器获取令牌和用户数据。令牌存储在本地存储中,用户数据存储在内存中(在顶级控制器的范围内)。在用户数据中,我有关于他的角色的信息,因此我可以检查他是否有权查看特定内容。

现在让我们假设用户已登录并重新加载页面。我仍然拥有令牌,因为它在 localStorage 中,但我丢失了用户数据(所以我不知道他的角色是什么)。在我再次从服务器获取他的数据之前,我不想向用户显示任何内容。所以我的问题是如何解决这个问题?我应该在何时何地向服务器请求用户数据?

我认为解决方案可能是手动引导应用程序。我试图做这样的事情:

app = angular.module('myApp', [])

fetchData = ->
	injector = angular.injector(['ng'])
	$http = injector.get('$http')
	API_URI = injector.get('API_URI')
	$localStorage = injector.get('$localStorage')

	$http.get("#{API_URI}/users/me?token=#{$localStorage.token}")
		.success (data) ->
			app.constant('USER_DATA', data)

bootstrapApplication = ->
	angular.element(document).ready ->
		angular.bootstrap(document, ['myApp'])

fetchData().then(bootstrapApplication)

此代码的问题是我无权访问 $localStorage 服务和 API_URI 常量。我需要他们获取令牌并动态更改 url(开发、生产)。

那么最好的解决方案是什么?也许也将用户角色存储在本地存储中?

任何帮助将不胜感激,谢谢。

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    您可以在路由配置中使用 Angular 的解析。这是一个示例,我正在为特定路线解析“用户”。它必须在 angular 加载这条路线之前解决。

    app.config( [ '$routeProvider', '$locationProvider',
        function( $routeProvider, $locationProvider ) {
    
            $routeProvider
                .when('/somePath', {
                    templateUrl: "someView.html",
                    controller: "someController",
                    resolve: {
                        user: function( authService ){
                            return authService.getUser();
                        }
                    }
                }
            );
    
        }
    ]);
    

    这是与之配套的服务(在本例中为工厂)。我正在检查 auth.user 是否首先存在,因此每次路由更改都不会有请求:

    app.factory('authService', [ '$http', '$q',
        function( $http, $q ) {
    
            var pub = {};
    
            pub.user = null;
    
            pub.getUser = function() {
    
                var deferred = $q.defer();
    
                if( pub.user ) {
                    deferred.resolve( pub.user );
                }
    
                else{
                    $http.get('/someAuthUrl').then(function( user ) {
                        pub.user = user;
                        deferred.resolve( user );
                    });
                }
    
                return deferred.promise;
    
            };
    
            return pub;
    
        }
    ]);
    

    最后是控制器,直到 auth 函数用您需要的用户数据解决后才会加载。您现在可以通过注入访问用户对象。

    app.controller( 'someController', [ '$scope', 'user',
        function( $scope, user ) {
    
            //Controller runs here only when user is resolved.
            // Anything resolved will be passed in as your last dependency.
            $scope.user = user;
    
        }
    ]);
    

    在这种情况下,您可以改为将服务注入控制器并使用 authService.user,因为我们知道它是可用的。

    app.controller( 'someController', [ '$scope', 'authService',
        function( $scope, authService ) {
    
            $scope.user = authService.user;
    
        }
    ]);
    

    【讨论】:

    • 感谢您的回答。我不喜欢这种方法的是,在我的案例中,我必须在每条路线上都进行用户解析。这是因为用户可以在 cms 中的每个位置刷新页面。 Resolve 也是邪恶的,好像服务器没有快速响应,用户可能认为应用程序没有响应,什么也没发生。
    • 您对使用resolve的负面因素提出了一些好处。我会再考虑一下,看看我是否能想出更好的解决方案。
    【解决方案2】:

    这是因为每当您重新加载/导航时,都会创建新的控制器实例并且您在控制器中的用户数据会丢失。最好的方法是将验证和存储数据的逻辑移动到服务中并在控制器中使用该服务,这样您就不会在刷新/导航时丢失数据

    【讨论】:

    • 在页面之间导航时保​​留用户数据没有问题。正如您提到的,用户数据实际上存储在单独的服务和控制器中,我只是将它们分配给范围。如果您将数据保留在服务中并不重要 -> 您仍然只在内存中拥有它们。所以在页面刷新时你会丢失它们。所以这是一个问题:即使用户刷新页面,如何管理用户数据以保留它们?
    • 这就是关键,如果您继续使用它就不会在刷新时丢失。
    • 我不这么认为。服务只在记忆中。因此,当您刷新页面时,必须再次重新创建服务。任何未保存在持久内存中的数据(如本地存储将丢失)。其他解决方案可能是再次向服务器询问用户数据。
    • 你能分享你的控制器和服务代码吗?顺便说一句,刷新我的意思是导航到新视图而不是完成页面刷新。完整的页面刷新当然会重新创建所有内容
    • 我明白了 :) 问题是关于完整的页面刷新,没有视图更改/刷新。在我检查用户角色(用户角色来自服务器)之前,我想知道如何再次从服务器检索用户数据。
    猜你喜欢
    • 2016-11-11
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 2017-12-08
    • 1970-01-01
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多