简体   繁体   English

如何为所有角度控制器固定或设置轨道样式的before_filter?

[英]how to secure or set a rails style before_filter for all angular controllers?

I'm using angularjs for the front end and rails + devise for authentication on the backend. 我在前端使用angularjs,在后端使用rails + devise进行身份验证。

On the front end I have added a responseInterceptor to redirect to the /#/sign_in page upon any 401 response from any xhr request and display a growl style pop-up message using toastr. 在前端,我添加了responseInterceptor,以便在来自任何xhr请求的任何401响应后重定向到/#/sign_in页面,并使用toastr显示咆哮样式弹出消息。

App.config(['$httpProvider', function ($httpProvider) {
  $httpProvider.responseInterceptors.push('securityInterceptor');
}]);

App.factory('securityInterceptor', ['$injector', '$location', '$cookieStore', function ($injector,$location,$cookieStore) {

  return function(promise) {
    var $http = $injector.get('$http');
      return promise.then(null, function(response){
        if (response.status === 401) {
          $cookieStore.remove('_angular_devise_user');
          toastr.warning('You are logged out');
          $location.path('/#/sign_in');
        }
      });
    };
});

My problem is, when I click on a page that loads several xhr requests during the controllers initialization, for example: 我的问题是,当我单击在控制器初始化期间加载多个xhr请求的页面时,例如:

var products = Product.query();
var categories = Category.query();
var variations = Variation.query();

These are needed for various navigation components and they all fire off in parallel, resulting in several duplicate growl-style messages. 这些是各种导航组件所必需的,它们都并行触发,从而导致出现几条重复的咆哮式消息。

Is there a way to make angular quit on the first 401 and stop execution of the rest of the controller from within the interceptor? 有没有办法在第一个401上退出角度并停止从拦截器内部执行其余控制器的工作? In a traditional rails app, there would be a "before_filter" that stops regular execution, preventing the page and queries from loading... what's the best way to do this in angular? 在传统的Rails应用程序中,将存在一个“ before_filter”来停止常规执行,从而阻止页面和查询的加载……最好的方法是按角度进行此操作?

I've been pondering about this problem for my own apps too. 我也一直在为自己的应用程序考虑这个问题。 A sketch of my thoughts (NOT REAL IMPLEMENTATION, SO BEWARE): 我的想法简述(不是真正的实现,因此请注意):

A userData service keeps track of whether the user is logged in + other information (eg user name, real user name etc): userData服务跟踪用户是否已登录以及其他信息(例如,用户名,真实用户名等):

App.service("userData", function() {
    var currentData = {
        loggedIn: false
    };

    function getCurrent() {
        return currentData;
    }

    // called when the user logs in with the user data
    function loggedIn(userData) {
        // the object is REPLACED to avoid race conditions, see explanation below
        currentData = angular.extend({loggedIn: true}, userData);
    }

    return {
        getCurrent: getCurrent,
        loggedIn: loggedIn
    };
});

The interceptors keep track of the currentData . 拦截器跟踪currentData If an interceptor receives HTTP 401 and the loggedIn flag is true , it changes the flag to false and redirects to the login view. 如果拦截器接收到HTTP 401并且loggedIn标志为true ,则它将标志更改为false并重定向到登录视图。 If an interceptor receives HTTP 401 and the loggedIn flag is false , it does nothing besides rejecting the request, because another interceptor has done the view redirection. 如果拦截器接收到HTTP 401并且loggedIn标志为false ,那么它除了拒绝请求外不会执行任何操作,因为另一个拦截器已经完成了视图重定向。

When the user logs in, the currentData is replaced, so as to avoid situations with delayed responses (eg call1 and call2 are initiated, call1 responds 401; call2 also results in 401, but the delivery of the actual response is delayed; then the user logs in again; then call2 receives its 401; the second 401 should not overwrite the current state) 当用户登录时, currentData被替换,以避免出现延迟响应的情况(例如,发起call1和call2,call1响应401; call2也导致401,但是实际响应的传递被延迟;然后用户再次登录;然后call2收到其401;第二个401不应该覆盖当前状态)

App.config(["$provide", "$httpProvider", function($provide, $httpProvider) {
    $provide.factory("myHttpInterceptor", ["$q", "userData", "$cookieStore", "toastr", "$location",
        function($q, userData, $cookieStore, toastr, $location) {
            return {
                request: function(config) {
                    config.currentUserData = userData.getCurrent();
                    return config;
                },
                responseError: function(rejection) {
                    if( rejection && rejection.status === 401 && rejection.config && rejection.config.currentUserData && rejection.config.currentUserData.loggedIn ) {
                        rejection.config.currentUserData.loggedIn = false;
                        $cookieStore.remove('_angular_devise_user');
                        toastr.warning('You are logged out');
                        $location.path('/#/sign_in');
                    }
                    return $q.reject(rejection);
                }
            };
        }
    ]);

    $httpProvider.interceptors.push("myHttpInterceptor");
});

Also note I am using the newer way to register interceptors, as $httpProvider.responseInterceptors seems to be deprecated. 还要注意,我正在使用更新的方法来注册拦截器,因为$httpProvider.responseInterceptors似乎已被弃用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM