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();        
        };
});
有帮助吗?

解决方案

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

其他提示

Does it work if you configure it globally?

module.config(function ($httpProvider) {
    $httpProvider.defaults.xsrfHeaderName = "X-CSRFToken";
    $httpProvider.defaults.xsrfCookieName = "csrftoken";
});
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top