質問

I have a very simple Resource like this for my model 'Presentacion'

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

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

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

And then in my 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 is working fine for the GET 'presentaciones/' requests but when I try to make a PUT request, I'm getting a 403 FORBIDDEN

What's strange to me is that GET is working fine: as long as I'm logged, it's responding correctly but if I logout it responds with 403 FORBIDDEN.

役に立ちましたか?

解決

If you are using Django's session based authentication, then you may be tripping over the CSRF protection built into Django (see UserLoggedInAuthentication class[1]).

If this is the case, you will need to ensure that a CSRF cookie gets sent to the client and then you can adapt the jQuery instructions[2] to send the X-CSRFToken header with requests that may change data.

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

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

他のヒント

If the issue is the X-CSRF token header you can modify the Backbone.sync like this to send a token with each 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);
        };

I realize this is an older post, but I was dealing with this problem recently. Expanding on @orangewarp's answer and using django documentation (https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax), here's a solution:

This solution uses the csrftoken cookie. Another solution would be to create a csrf token endpoint in your API and grab the 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);
  };
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top