简体   繁体   中英

Django csrf token + Angularjs

I have django running on an apache server using mod_wsgi, as well as an angularjs app served directly by apache, not by django. I would like to make POST calls to the django server (running rest_framework) but I am having problems with the csrf token.

Is there someway to set the token from the server without putting {% csrf token %} as part of the template (since these pages aren't going through django)?

  1. I would like to be able to get a csrf token through a GET request as a cookie.
  2. I would like to be able to then make POST requests to the django server with the csrf token cookie value.

Django and AngularJS both have CSRF support already, your part is quite simple.

First, you need to enable CSRF in Django, I believe you have already done so, if not, follow Django doc https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/#ajax .

Now, Django will set a cookie named csrftoken on the first GET request and expects a custom HTTP header X-CSRFToken on later POST/PUT/DELETE requests.

For Angular, it expects the cookie named XSRF-TOKEN and will do POST/PUT/DELETE requests with X-XSRF-TOKEN header, so you need to do a little bit tweak to make the two go with each other:

$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';

Add above two lines somewhere in your js code, module.config() block is a good place for this.

That's it.

NOTE: This is for angular 1.1.5, older versions might need different approach.

Update:

Since the angular app isn't served by django, in order to let the cookie to be set, angular app needs to do a GET request to django first.

var foo = angular.module('foo', ['bar']);

foo.config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.xsrfCookieName = 'csrftoken';
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);

And all modules services and controllers, where $http used, will send requests with csrf token.

After searching around, what worked for me was from this post with the following code:

angular.module( '[your module name]',
    ... [some dependencies] ...
    'ngCookies',
    ... [other dependencies] ...
)
.run( function run( $http, $cookies ){

    // For CSRF token compatibility with Django
    $http.defaults.headers.post['X-CSRFToken'] = $cookies.get('csrftoken');
})

This is of course after getting the cookie through a GET request from the django server.

I also looked into some of the other answers here, including Ye Liun's but couldn't find anything in the official docs specifying changes to the defaults options for xsrf on $httpProvider, other than this pull request which didn't work for me at the time of me writing this post.

I created a Django App for my AngularJS app, in the same Django project as my (REST) API Django App, that only serves the index.html file (which is just a sym.link). In this way the CSRF Cookie is set without an additional GET request.

Please see my answer here about AngularJS Single Page Web Application on Sub-domain A talking to a Django JSON (REST) API on Sub-domain B using CORS and CSRF protection

If you have your cookies set to disallow javascript access, you need to do the following. In your template, before creating the django app, add this:

<script>
    window.csrf_token = "{{ csrf_token }}";
</script>

In your angular app, add this:

angularApp.config(["$httpProvider", function($httpProvider) {
    $httpProvider.defaults.headers.common["X-CSRFToken"] = window.csrf_token;
}]);

At least through Django 1.9, the CSRF token does not change with each request. It only changes when a user logs in. If you are doing a single page angular app, you need to make sure you reset the token on login/logout and this should work fine.

NOTE: This does not currently work in Django 1.10 or later due to the CSRF token changing on each request. See Pass Django CSRF token to Angular with CSRF_COOKIE_HTTPONLY

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM