Here’s the scenario, I am working on an application that uses Django REST Framework in the backend. On the front end I use AngularJS with ngResource. The application is expected to have a web front end and mobile applications in the future. So I chose both BasicAuthentication and SessionAuthentication as default authentication options. BasicAuthentication uses the basic HTTP Auth to verify the user and is suitable for mobile devices. And SessionAuthentication uses the default Django session. Since I have a web front end, SessionAuth comes very handy – I don’t need to send auth data on every request if the user is logged in already.
This works excellent for GET or HEAD requests but things get rough when you need to make a POST, PUT or DELETE request. SessionAuthentication depends on the CSRF token mechanism built into Django. Django requires a special header to be sent with the csrf token. Details are on the Django docs – https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/#ajax.
Getting the cookie and parsing the csrf token part is rather simple. I ported the jQuery version to a generic JavaScript version just by replacing jQuery.trim() with String.prototype.trim() –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie != '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = cookies[i].trim(); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) == (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } |
Now, ngResource or $resource isn’t very customizable compared to the $http component and most people suggested me to use the latter. Just when I was about to lose hope and planning to rewrite my own wrappers around $http, I just came to realize that $resource is also based on $http. If I can change the global $http config to push the header, $resource will also use the same header. So, I configured things like this –
1 2 3 4 5 6 7 |
var service = angular.module("apiService", ["ngResource", "ui.bootstrap"]); service.config(["$httpProvider", function (provider) { provider.defaults.headers.post["X-CSRFToken"] = getCookie('csrftoken'); } ]); |
And finally it works! 😀 Now, every POST request made using $http will have that extra header. But I don’t mind since my application is probably not going to make POST requests to any alien servers 🙂
8 replies on “Django REST Framework, AngularJS and SessionAuthentication”
hello brother,
how do you write code on your page in this style (highlighting the syn-taxes).
I use Wp-Crayon plugin. I customized the theme and font.
Also you can use native module ngCookies. Thus you shall add mere one line:
And don’t forget to include the angular-cookies.js file in your html-file!
Hi Alex,
Brilliant suggestion. Thanks a lot 🙂
— Masnun
Hello, i had (have) the same issue.
Are your angular app wrapped in the django app?
I ask cause I have my angular app separated from django. So, I couldn’t use {% csrf_token %} and found no other way to create the cookie.
My solution was to use tokenauth instead, but I have to send the token on every request.
Thanks
Yes, the web front end is luckily wrapped in django.
Hi, I found next approach:
myApp.config(['$httpProvider', '$interpolateProvider',
function($httpProvider, $interpolateProvider) {
/* for compatibility with django teplate engine */
$interpolateProvider.startSymbol('{$');
$interpolateProvider.endSymbol('$}');
/* csrf */
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
}]);
Muchas gracias! asà es!