Django 2.0 IPN回调遇Forbidden(CSRF cookie未设置),加@csrf_exempt仍无效
Hey there, I’ve dealt with this exact frustration before—when you swear you added @csrf_exempt but Django still throws that CSRF error. Let’s break down the most common reasons this happens and how to fix them:
1. You’re using the wrong decorator order (for function views)
If your IPN view uses other decorators like @require_POST, the order matters a lot. @csrf_exempt needs to be the outermost decorator so it takes priority. Here’s the correct setup:
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST from django.http import HttpResponse @csrf_exempt @require_POST def ipn_view(request): # Your IPN processing logic here return HttpResponse("Success")
If you put @require_POST above @csrf_exempt, Django will first check the request method before skipping CSRF validation, which can still trigger the error.
2. You’re using a class view and didn’t apply the decorator correctly
Class views don’t work with @csrf_exempt directly—you need to wrap it with method_decorator and target the dispatch method (the entry point for all class view requests). Here are two valid ways to do this:
Option 1: Decorate the entire class
from django.views import View from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator from django.http import HttpResponse @method_decorator(csrf_exempt, name='dispatch') class IPNView(View): def post(self, request): # Your IPN logic return HttpResponse("Success")
Option 2: Decorate the dispatch method directly
class IPNView(View): @method_decorator(csrf_exempt) def dispatch(self, *args, **kwargs): return super().dispatch(*args, **kwargs) def post(self, request): # Your IPN logic return HttpResponse("Success")
Skipping this and just adding @csrf_exempt to the post method won’t work—Django checks CSRF before reaching the specific HTTP method handler.
3. A URL-level decorator is overriding your view’s exemption
Double-check your URL configuration to make sure you didn’t add csrf_protect to the IPN route. For example, this would override your view’s @csrf_exempt:
# urls.py (bad example) from django.views.decorators.csrf import csrf_protect from .views import ipn_view urlpatterns = [ path('ipn/', csrf_protect(ipn_view), name='ipn_handler'), ]
Remove any csrf_protect decorators from the IPN URL entry to let your view’s exemption take effect.
4. Middleware is enforcing CSRF checks after CsrfViewMiddleware
Check your settings.py MIDDLEWARE list. If you have a custom middleware or third-party security middleware that runs after django.middleware.csrf.CsrfViewMiddleware, it might be re-applying CSRF validation. Ensure:
CsrfViewMiddlewareis present in the list- No subsequent middleware is overriding the exemption (look for any middleware related to security or request validation)
5. Old code is cached (server or application-level)
Sometimes the issue is just stale code. Try:
- Restarting your Django development server (or production server like Gunicorn/UWSGI)
- Clearing any server-side caches (e.g., Nginx, Apache)
- Making sure your code deployment actually pushed the updated view with the correct decorator
Give these steps a try—most of the time, it’s either a decorator order/placement issue or a URL/middleware conflict.
内容的提问来源于stack exchange,提问作者chaica

