ottercoder
ottercoder

Reputation: 862

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?

Upvotes: 0

Views: 341

Answers (2)

DerekMT12
DerekMT12

Reputation: 1349

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$/
    ]);
}

Upvotes: 1

Ankit Singh
Ankit Singh

Reputation: 121

There is a better way of doing this. After login in set the auth token into the header of $http service. So that you don't need to pass the config object in each call.

Login :

function Login(credentials){
    $http.post(apiPath, credentials).then(function (data) {
         $http.defaults.headers.common['Authorization'] = data['token'];
    });
}

All the HTTP calls after this will have Authorization header set.

But there are some call which doesn't require Authorization in those cases you can write a function which have its own config object passed without Authorization in the header.

Function without Authorization:

function Without_Auth(url, data) {
    var deferred = $q.defer();
    var responsePromise = $http({
        method: 'post',
        url: url,
        data: data,
        headers: {
            'Content-Type': 'application/json;charset=utf-8;'
        }
    })
    responsePromise.success(function (data) {
        deferred.resolve(data);
    });
    responsePromise.error(function (err) {
        deferred.reject();
    });
    return deferred.promise;
}

Hope this solves your problem!

Upvotes: 1

Related Questions