Search code examples
javascriptangularjstokeninterceptorangular-http-interceptors

How to split interceptor for different requests (URLs)?


At first I've had configAuth with headers, including JWT token at every Controller.

var configAuth = {
    headers: {
        'Content-Type': 'application/json',
        'Authorization': localStorage.getItem('token')
    }
};

But now when I have great ammount of Controllers, I realized that I need to do something about it. I've heard about interceptors and trying to get them.

I know that I can't just put token to every request, because there's some pages and requests like /login that shouldn't have Authorization token at all. And getting html files with Authorization header is somehow giving me an exception. So I've tried to split requests like that:

angular.module('App')

.factory('sessionInjector',['$injector', function ($injector) {
    var sessionInjector = {
        request: function (config) {
            if (config.url == "/one" || config.url == "/two"){
                config.headers['Content-Type'] = 'application/json;charset=utf-8;';
                config.headers['Authorization'] = localStorage.getItem('token');
            } else {
                config.headers['Content-Type'] = 'application/json;charset=utf-8;';
            }
            return config;
        },
        response: function(response) {
            if (response.status === 401) {
                var stateService = $injector.get('$state');
                stateService.go('login');
            }
            return response || $q.when(response);
        }
    };
    return sessionInjector;
}]);

But it doesn't work with requests like /one/{one_id} and I can't hardcode all the possibilities. So what is the best practice for this?


Solution

  • What you have now is a good starting point. I'm assuming the majority of your APIs will need the auth token, so setting up which endpoints don't require auth would probably be the quicker path. I haven't tested this, but it might get you on the right track. I setup your injector as a provider so you can configure the anonymous route rules within the config.

    angular.module('App')
        .provider('sessionInjector',[function () {
            var _anonymousRouteRules;
    
            this.$get = ['$injector', getSessionInjector];
            this.setupAnonymousRouteRules = setupAnonymousRouteRules;
    
            function getSessionInjector($injector) {
                var service = {
                    request: requestTransform,
                    response: responseTransform
                };
    
                function requestTransform(config) {         
                    if (!isAnonymousRoute(config.url)){
                        config.headers['Authorization'] = localStorage.getItem('token');
                    }
    
                    config.headers['Content-Type'] = 'application/json;charset=utf-8;';
    
                    return config;
                }
    
                function responseTransform(response) {
                    if (response.status === 401) {
                        var stateService = $injector.get('$state');
                        stateService.go('login');
                    }
                    return response || $q.when(response);
                }
    
                return service;
            }
    
            function isAnonymousRoute(url) {
                var isAnonymous = false;
                angular.forEach(_anonymousRouteRules, function(rule) {
                    if(rule.test(url)) {
                        isAnonymous = true;
                    }
                });
                return isAnonymous;
            }
    
            function setupAnonymousRouteRules(anonymousRouteRules) {
                _anonymousRouteRules = anonymousRouteRules;
            }
        }]);
    

    With this, you can configure the rules by passing in an array of regexes for your urls:

    angular.module('App').config(['sessionInjectorProvider', config]);
    
    function config(sessionInjectorProvider) {
        sessionInjectorProvider.setupAnonymousRouteRules([
            /.*\.html$/,
            /^\/login$/
        ]);
    }