【问题标题】:how to secure or set a rails style before_filter for all angular controllers?如何为所有角度控制器保护或设置 rails 样式 before_filter?
【发布时间】:2013-09-17 22:23:42
【问题描述】:

我在前端使用 angularjs,在后端使用 rails + devise 进行身份验证。

在前端,我添加了一个 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');
        }
      });
    };
});

我的问题是,当我在控制器初始化期间单击加载多个 xhr 请求的页面时,例如:

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

这些是各种导航组件所必需的,并且它们都并行触发,从而导致多个重复的咆哮式消息。

有没有办法在第一个 401 上进行角度退出并从拦截器中停止执行控制器的其余部分?在传统的 Rails 应用程序中,会有一个“before_filter”停止常规执行,阻止页面和查询加载......在 Angular 中执行此操作的最佳方法是什么?

【问题讨论】:

    标签: ruby-on-rails authentication angularjs devise interceptor


    【解决方案1】:

    我也一直在为自己的应用考虑这个问题。我的想法的草图(不是真正的实现,所以要小心):

    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
        };
    });
    

    拦截器跟踪currentData。如果拦截器收到 HTTP 401 并且 loggedIn 标志是 true,它会将标志更改为 false 并重定向到登录视图。如果一个拦截器接收到 HTTP 401 并且loggedIn 标志是false,它除了拒绝请求之外什么都不做,因为另一个拦截器已经完成了视图重定向。

    当用户登录时,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");
    });
    

    另外请注意,我正在使用更新的方式来注册拦截器,因为 $httpProvider.responseInterceptors 似乎已被弃用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-27
      • 2016-09-04
      • 1970-01-01
      • 1970-01-01
      • 2011-12-22
      • 2018-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多