AngularJs全局消息服务和身份验证

AngularJs全局消息服务和身份验证,angularjs,Angularjs,我有一个消息系统,它有两种方法show和clear。我想使用$http拦截器来处理身份验证,因为我的服务器足够聪明,可以知道每个请求是否对用户进行了身份验证,并通过向我发送401或403的状态响应来告诉我。我的拦截器是这样的: myModule.factory('statusInterceptor', function($location, MessageService, urlManager){ return { responseError: function(resp

我有一个消息系统,它有两种方法
show
clear
。我想使用$http拦截器来处理身份验证,因为我的服务器足够聪明,可以知道每个请求是否对用户进行了身份验证,并通过向我发送
401
403
的状态响应来告诉我。我的拦截器是这样的:

myModule.factory('statusInterceptor', function($location, MessageService, urlManager){
    return {
        responseError: function(response){
            switch(response.status){
                ...
                case 401:
                case 403:
                    $location.url(urlManager.reverse('Login'));
                    MessageService.show('Dude, you need to log in first.');
                    break;
                case 500:
                    break;
                ...
            }
            return response;
        }
    };
});
这在
401
403
响应上都可以正常工作,因为它按预期显示消息。我遇到的问题是,每当用户登录或转到其他路由时,都会清除消息。我有一个
MainCtrl
,它负责几乎所有的事情,它正在处理的事情之一是
$routeChangeStart
。我的想法是视图正在更改为另一个视图,因此我想清除路由开关开头的消息。因此,在我的
MainCtrl
中,我有:

myControllers.controller('MainCtrl', function($scope, MessageService){
    $scope.$on('$routeChangeStart', function(){
        MessageService.clear();
    });
});
以下是我期望应用程序的反应方式:

  • 通过向服务器发送请求,用户试图在未经身份验证的情况下执行某些操作
  • 服务器以
    401
    403
    响应,因为用户未经身份验证
  • 调用my
    $location.url()
    方法将触发
    responseError
    函数,在我看来,该方法应该触发
    $routeChangeStart
    ,甚至
    $locationChangeStart
    事件(我已经尝试了这两种方法)。
    • 这将依次触发我的
      MessageService.clear()
      方法并清除以前的任何消息
  • 用户最终被重定向到登录页面,并显示正确的
    “Dude,您需要先登录。”
    消息
  • 实际发生的情况:


    用户将按预期重定向到登录页面,但不会显示错误消息。在Chrome中设置某些调试点时,我看到调用
    $location.path()
    后紧接着调用
    MessageService.show('Dude…')
    ,最后是
    MessageService.clear()
    调用。

    我终于找到了一个解决方案,结果是这样的:

    在我的拦截器函数中:

    myModule.factory('statusInterceptor', function($rootScope){
        return {
            responseError: function(response){
                switch(response.status){
                    ...
                    case 401:
                    case 403:
                        $rootScope.$broadcast('event:notAuthenticated');
                        break;
                    case 500:
                        break;
                    ...
                }
                return response;
            }
        };
    });
    
    在我的控制器中:

    myControllers.controller('MainCtrl', function($scope, $location, MessageService){
        $scope.$on('event:notAuthenticated', function(){
            $location.path(urlManager.reverse('Login'));
            var remove_this_binding = $scope.$on('$routeChangeSuccess', function(){
                messageService.show('Dude, you need to log in first.');
                remove_this_binding();
            });
        });
        $scope.$on('$routeChangeStart', function(){
            messageService.clear();
        });
    });
    

    我试图找到一种有角度的方法,使回调与
    $location
    的路径更改相关联,这是我能想到的最好的方法。如果其他人有更好的解决方案,我洗耳恭听。

    也许你喜欢这种解决问题的方法


    关于

    我喜欢使用$q承诺。我不知道除了请求/响应事件之外,您还可以使用它。那么,$q只是一种更简单/更整洁的回调方式?
    module.factory('authenticationInterceptor', function ($q, navigator, MessageService) {
        return {
            responseError: function (response) {
                switch (response.status) {
                    case 403:
                        navigator.navigateTo("/login").then(function () {
                            MessageService.show('Dude, you need to log in first.');
                        });
                        return $q.reject(response);
                }
                return response;
            }
        };
    });
    module.factory("navigator", function ($location, $rootScope, $q) {
    
        var navigateTo = function (url) {
            var defered = $q.defer();
            $location.url(url);
            var unbind = $rootScope.$on('$routeChangeSuccess', function () {
                defered.resolve();
                unbind();
            })
            return defered.promise;
        }
        return {
            navigateTo: navigateTo
        }
    });