79
class ChromeLoginView(View):

     def get(self, request):
          return JsonResponse({'status': request.user.is_authenticated()})

     @method_decorator(csrf_exempt)
     def post(self, request):
          username = request.POST['username']
          password = request.POST['password']
          user = authenticate(username=username, password=password)
          if user is not None:
                if user.is_active:
                     login(request, user)
                     return JsonResponse({'status': True})
          return JsonResponse({'status': False})

I am expecting that the post does stopped by csrf, but it return 403 error.

But if remove that decorator and do this in the URLConf

url(r'^chrome_login/', csrf_exempt(ChromeLoginView.as_view()), name='chrome_login'),

it will work.

What happened here? didn't it supposed to work, because I guess that's what method_decorator do. I'm using python3.4 and django1.7.1

Any advice would be great.

Feuermurmel
  • 9,490
  • 10
  • 60
  • 90
castiel
  • 2,675
  • 5
  • 29
  • 38
  • 1
    You should look into the django_braces... – rnevius Dec 05 '14 at 13:28
  • 1
    It's super awesome! Especially since you can simply add the [CsrfExemptMixin](https://django-braces.readthedocs.org/en/v1.4.0/form.html#csrfexemptmixin) to your view to make this work. It's almost like cheating... – rnevius Dec 05 '14 at 14:37
  • In my use case I am not using a form, so how can I still include a csrf token in my application? Like I am creating APIs hence a UI doesn't come into picture. So how can I make sure that CSRF token is still passed? – Apurva Kunkulol Sep 30 '17 at 10:41
  • These answers won't work for DRF. See https://stackoverflow.com/questions/30871033/django-rest-framework-remove-csrf – Boris Verkhovskiy Aug 28 '20 at 17:29

4 Answers4

137

As @knbk said, this is the dispatch() method that must be decorated.

Since Django 1.9, you can use the method_decorator directly on a class:

from django.utils.decorators import method_decorator

@method_decorator(csrf_exempt, name='dispatch')
class ChromeLoginView(View):

    def get(self, request):
        return JsonResponse({'status': request.user.is_authenticated()})

    def post(self, request):
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user is not None:
            if user.is_active:
                login(request, user)
                return JsonResponse({'status': True})
        return JsonResponse({'status': False})

This avoids overriding the dispatch() method only to decorate it.

Lord Elrond
  • 13,430
  • 7
  • 40
  • 80
Antoine Pinsard
  • 33,148
  • 8
  • 67
  • 87
100

You need to decorate the dispatch method for csrf_exempt to work. What it does is set an csrf_exempt attribute on the view function itself to True, and the middleware checks for this on the (outermost) view function. If only a few of the methods need to be decorated, you still need to use csrf_exempt on the dispatch method, but you can use csrf_protect on e.g. put(). If a GET, HEAD, OPTIONS or TRACE HTTP method is used it won't be checked whether you decorate it or not.

class ChromeLoginView(View):
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(ChromeLoginView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return JsonResponse({'status': request.user.is_authenticated()})

    def post(self, request):
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user is not None:
            if user.is_active:
                login(request, user)
                return JsonResponse({'status': True})
        return JsonResponse({'status': False})
knbk
  • 52,111
  • 9
  • 124
  • 122
5

If you are looking for Mixins to match your needs, then you can create a CSRFExemptMixin and extend that in your view no need of writing above statements in every view:

class CSRFExemptMixin(object):
   @method_decorator(csrf_exempt)
   def dispatch(self, *args, **kwargs):
       return super(CSRFExemptMixin, self).dispatch(*args, **kwargs)

After that Extend this in your view like this.

class ChromeLoginView(CSRFExemptMixin, View):

You can extend that in any view according to your requirement, That's reusability! :-)

Cheers!

vikas0713
  • 566
  • 7
  • 9
2

Django braces provides a CsrfExemptMixin for this.

from braces.views import CsrfExemptMixin

class ChromeLoginView(CsrfExemptMixin, View):
    ...
Llanilek
  • 3,386
  • 5
  • 39
  • 65