1

I am learning to work with Django Rest Framework and following the tutorial. I have create a simple index based on the tutorial, that works for GET, but not for POST:

@api_view(['GET','POST'])
def game_list(request):
    if request.method == 'GET':
        games = Game.objects.all()
        serializer = GameSerializer(games, many=True)
        return Response(serializer.data)
    elif request.method == 'POST':
        serializer = GameSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

I set the default settings to AllowAny:

REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny'
    ]
}

but I still get a HTTP 403 when I try to POST anything, using the Firefox RESTClient. I read that I have to add a X-CSRFToken header and cookie for this to work, but I do not have those.

Community
  • 1
  • 1
Bart Friederichs
  • 33,050
  • 15
  • 95
  • 195
  • What do you mean by "I do not have those"? You don't have CSRF protection enabled? Have you tried with [`csrf_exempt`](https://docs.djangoproject.com/en/1.9/ref/csrf/#django.views.decorators.csrf.csrf_exempt)? – Andrea Corbellini Dec 04 '15 at 21:33
  • you have to pass that along with your post request. It exists in the session when you visit any page in your website and can be seen as a cookie. https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax – Chris Hawkes Dec 04 '15 at 21:33
  • @ChrisHawkes I get that, but I want to understand exactly what is going on. The RESTClient sends only headers I put in myself. I have no session information at all on this. When I do a clean `GET`, I get no cookies or session information in response headers. – Bart Friederichs Dec 04 '15 at 21:35
  • the csrftoken I think is only required on the post, however for testing like the previous commenter said you can make that method call on your view exempt from csrf – Chris Hawkes Dec 04 '15 at 21:37
  • @ChrisHawkes yes, that might work in the previous step ;-)). I continued with my tutorial and the `APIView` doesn't seem to support the `@csrf_exempt` annotation ... – Bart Friederichs Dec 04 '15 at 21:41

1 Answers1

0

From documentation:

By default, a ‘403 Forbidden’ response is sent to the user if an incoming request fails the checks performed by CsrfViewMiddleware. This should usually only be seen when there is a genuine Cross Site Request Forgery, or when, due to a programming error, the CSRF token has not been included with a POST form.

Also, as stated if the official documentation, CSRF is enabled by default, and you need to add a X-CSRFToken in your AJAX requests.

Here is the code from the documentation:

// using jQuery
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;
}

var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

Take in mind that the documentation suggest to use ajaxSetup method from jquery, which is not a recommended way to do it because it can alter the way that others scripts uses the ajax function, so it's better to add the specific CSRF's code in your custom JS code like this:

$.ajax({
    method: 'POST',
    url: 'your.url.com/',
    beforeSend: function(xhr, settings) {
        if (!WU._csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    },
    success: function(msg)
    {}
});

Reference: https://docs.djangoproject.com/en/1.9/ref/csrf/#ajax

Ciro Pedrini
  • 4,135
  • 1
  • 11
  • 17