Question

Currently by using the setTimeout method I am able to successfully do what i want to. But this is not the ideal approach.

When we send a login request, we want to get the CSRF token from the response header and use it insubsequent http calls. The http.get() request does that for us(it sets the login's response header into request header). After that we want to do a post request again based on the response we get from the http.get() request inside the login callback.

The problem here is that the code gets executed before the browser finishes, setting the CSRF token received from response into the request header. In order to overcome this problem, I added a setTimeout function. But I don't really like the approach of adding a hardcoded delay.

Is there any efficient way of doing this?

        app.controller('loginCtrl', function ($scope, $http, $location, $cookies, $q, Cart,$rootScope)
{
        var defer = $q.defer();

        $scope.submit = function(){

                $http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;application/JSON";
                //login
                $http.post('http://127.0.0.1:8000/api/user/login/', JSON.stringify({'email': $scope.email, 'password': $scope.password})
                ).success(function(data){

                defer.promise.then(function(){
                //need to get a cart to check if a cart is created
                    Cart.getCart(function(data){


                    defer.promise.then(function(){
               //if cart not created create one
                        if(data.length == 0){
                            setTimeout(function(){
                                $http.defaults.headers.common["X-CSRFToken"] = $cookies.csrftoken;
                                Cart.addCart(function(data){
                                    alert('cart successfully created \n ' + JSON.stringify(data));
                                    $rootScope.cartId = data[0].pk
                                    $rootScope.cart = data[0].fields;
                                    $location.path('/products');
                                }, function(error){
                                    alert('addcart failed');
                            });
                            },300);

                        } else {
                            $rootScope.cartId = data[0].pk;
                            $rootScope.cart = data[0].fields;
                            $location.path('/products');
                        }

             })

                }, function(error){
                    alert('getcart failed');
                });
            })
                //need code to get the cookies, still dont know how

                }).error(function(data){
                alert('failure');
                });


        defer.resolve();        
        };
});
Was it helpful?

Solution

Maybe you could intercept the response, parse the headers and set the token manually.

Something like this:

module.factory('xsrfTokenInterceptor', function ($q, $http) {
    return {
        'response': function (response) {
            var cookies = response.headers("Set-Cookie");
            var token = someCrazyParsing(cookies);
            $http.defaults.headers.common["X-CSRFToken"]=token;
            return response || $q.when(response);
        }  
    };
});
module.config(function($httpProvider){
    $httpProvider.interceptors.push('xsrfTokenInterceptor')
})

EDIT NEW APPROACH

Maybe something like this?

module.factory('LoginService', function ($q, $http) {
    var login = function (email, password) {
        var defered = $q.defer();
        $http.post('http://127.0.0.1:8000/api/user/login/', {
                'email': email,
                'password': password
        }).success(function (data, status, headers, config) {
            var cookies = headers("Set-Cookie");
            var token = someCrazyParsing(cookies); //<-- Your magic here
            $http.defaults.headers.common["X-CSRFToken"] = token;
            defered.resolve(data);
        }).error(function (data, status, headers, config) {
            defered.reject(data);
        });
        return defered.promise;
    };
    return {
        login: login
    };
});

module.controller("LoginCtrl", function ($scope, LoginService, Cart) {
    $scope.submit = function () {
        LoginService.login($scope.email, $scope.password).then(function (data) {
            Cart.getCart(function (data) {});
        });
    };
});

OTHER TIPS

Does it work if you configure it globally?

module.config(function ($httpProvider) {
    $httpProvider.defaults.xsrfHeaderName = "X-CSRFToken";
    $httpProvider.defaults.xsrfCookieName = "csrftoken";
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top