5
votes

I have developed a simple webservice, but failed to use post with Django Rest Framework as it complains about CSRF:

"detail": "CSRF Failed: CSRF cookie not set."

Removing the api_view decorator does stop the message from appearing but then I won't be able to access the request.data. I think that the api_view does check CSRF although I added the csrf_exempt decorator.

This is my view:

@permission_classes((IsAuthenticated, ))
@csrf_exempt
@api_view(['POST'])
def get_stats(request):
    """
    Returns the stats available.
    """

    user = request.user

    if request.method == 'POST':
        serializer = StatsRequestSerializer(data=request.data)
        stats_request = serializer.data
        return JSONResponse(stats_request)

            #serializer = QuizSerializer(user.quizes.all(), many=True)
            #return JSONResponse(serializer.data)

    response = ActionResponse(status='error', error='Invalid request')
    serializer = ActionResponseSerializer(response)
    return JSONResponse(serializer.data, status=400)

This is my model:

class StatsRequest(models.Model):
    """
    A model which describes a request for some stats for specific users.
    """

    start_date = models.DateField()
    end_date = models.DateField()

and this is my request POST:

{"start_date" : "1992-01-15", "end_date" : "1992-01-15" }

Any ideas?

More info:

AUTHENTICATION_BACKENDS = (
    'social.backends.facebook.FacebookOAuth2',
    'social.backends.google.GoogleOAuth2',
    'django.contrib.auth.backends.ModelBackend'
)
3
With every POST request, you need to send along a crsf-token. There are some more infos about this in the docs docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajaxHinrich
@Hinrich : that's the point of the csrf_exempt decorator: bypassing csrf validation, cf docs.djangoproject.com/en/1.8/ref/csrf/…bruno desthuilliers
Have you tried the api_view decorator without csrf_exempt? What authentication backend are you using?Alasdair
I have tried, not working still. I have added the authentication backends I'm using. BTW, for this specific request I'm using the session authentication with cookies.Shynet

3 Answers

1
votes

So, after trying to figure this out for a couple of hours I finally did it. Tracing the source code of DRF and Django lead me to believe that I need to find a workaround for this as the CSRF verification is made explicitly even if turned off, probably the CSRF check is being made at the api_view decorator. So I simply created my own decorator:

from functools import wraps
from django.utils.decorators import available_attrs, decorator_from_middleware

def csrf_clear(view_func):
    """
    Skips the CSRF checks by setting the 'csrf_processing_done' to true.
    """

    def wrapped_view(*args, **kwargs):
        request = args[0]
        request.csrf_processing_done = True
        return view_func(*args, **kwargs)

    return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)

and my view with the new decorator:

@csrf_clear
@api_view(['POST'])
@permission_classes((IsAuthenticated, ))
def get_stats(request):
    """
    Returns the stats available.
    """

    user = request.user

    if request.method == 'POST':
        serializer = StatsRequestSerializer(data=request.data)

        if serializer.is_valid():
            stats_request = serializer.data
            return JSONResponse(stats_request)

            #serializer = QuizSerializer(user.quizes.all(), many=True)
            #return JSONResponse(serializer.data)

    response = ActionResponse(status='error', error='Invalid request')
    serializer = ActionResponseSerializer(response)
    return JSONResponse(serializer.data, status=400)
0
votes

urls.py

from django.views.decorators.csrf import csrf_exempt
urlpatterns = [
    url(r'^snippets/$', views.SnippetList.as_view()),
    url(r'^snippets/(?P<pk>[0-9]+)/$', csrf_exempt(views.SnippetDetail.as_view())),

]

views.py

from django.views.decorators.csrf import csrf_exempt
from rest_framework.views import APIView
class SnippetList(APIView):
    @csrf_exempt
    @need_post_parameters([PARAM_MESSAGE_OBJ])
    def post(self, request, *args, **kwargs):
        data = request.POST.get(PARAM_MESSAGE_OBJ)

        try:
            message_obj = json.loads(data)
        except Exception as e:
            return HttpResponseBadRequest(error_json("Could not parse JSON"))

http://www.chenxm.cc/post/509.html