Django rest structure - authentication error with PUT requests

I have a very simple resource similar to this for my 'Presentacion' model

class PresentacionResource(ModelResource): model = Presentacion fields = (some fields) ignore_fields = (few to ignore) 

and I need to implement authentication for this, since I read, I created two wrappers

 class AuthListOrCreateModelView(ListOrCreateModelView): permissions = (IsAuthenticated, ) class AuthInstanceModelView(InstanceModelView): permissions = (IsAuthenticated, ) 

And then in mine in my urls.py

 url(r'^presentaciones/$', AuthListOrCreateModelView.as_view(resource=PresentacionResource), name='presentacion-root'), url(r'^presentaciones/(?P<id>[0-9]+)$', AuthInstanceModelView.as_view(resource=PresentacionResource), name='presentacion'), 

This works fine for 'presentaciones /' GET requests, but when I try to make a PUT request, I get 403 FORBIDDEN

What is strange to me is that GET works fine: as long as I am registered, it answers correctly, but if I log out, it answers 403 FORBIDDEN.

+2
django django-rest-framework
source share
3 answers

If you use authentication based on a Django session, you can disconnect from the CSRF protection built into Django (see the UserLoggedInAuthentication class [1]).

If so, you need to make sure that the CSRF cookie is sent to the client, and then you can adapt the jQuery [2] instructions to send the X-CSRFToken header with requests that can modify the data.

[1] http://django-rest-framework.org/_modules/authentication.html

[2] https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

+3
source share

If the problem is the X-CSRF token header, you can change Backbone.sync to send a token with every POST, PUT, DELETE request.

  /* alias away the sync method */ Backbone._sync = Backbone.sync; /* define a new sync method */ Backbone.sync = function(method, model, options) { /* only need a token for non-get requests */ if (method == 'create' || method == 'update' || method == 'delete') { // CSRF token value is in an embedded meta tag var csrfToken = $("meta[name='csrf_token']").attr('content'); options.beforeSend = function(xhr){ xhr.setRequestHeader('X-CSRFToken', csrfToken); }; } /* proxy the call to the old sync method */ return Backbone._sync(method, model, options); }; 
+9
source share

I understand that this is an older post, but I recently dealt with this issue. Extending @ orangewarp's answer and using the django documentation ( https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax ) here is the solution:

This solution uses the csrftoken cookie. Another solution would be to create a csrf marker endpoint in your API and capture csrf from there.

  Backbone._sync = Backbone.sync; Backbone.sync = function(method, model, options) { //from django docs 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 = jQuery.trim(cookies[i]); // 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; } /* only need a token for non-get requests */ if (method == 'create' || method == 'update' || method == 'delete') { var csrfToken = getCookie('csrftoken'); options.beforeSend = function(xhr){ xhr.setRequestHeader('X-CSRFToken', csrfToken); }; } return Backbone._sync(method, model, options); }; 
+2
source share

All Articles