You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

禁用POST请求CSRF防护后仅单个视图抛出Forbidden (CSRF cookie not set.)

问题

我正在使用Django REST framework和simplejwt认证开发Django后端,为适配React Native移动应用已禁用视图的CSRF防护。但其他视图均正常工作,唯独自定义的Token黑名单视图抛出Forbidden (CSRF cookie not set.)错误。

正常工作的视图示例:

@method_decorator(csrf_exempt, name='dispatch')
class BusinessProfileView(APIView):
    permission_classes = (permissions.IsAuthenticated, HasAccountOwnershipBP)
    
    def post(self, request, format='json'):
        serializer = BusinessProfileSerializer(data=request.data, context={'request': request})
        if serializer.is_valid():
            ...
    
    def put(self, request, format='json'):
        ...

抛出错误的Token黑名单视图:

@method_decorator(csrf_exempt, name='dispatch') 
class BlackListToken(APIView):
    permission_classes = (permissions.IsAuthenticated,)

    def post(self, request):
        refresh = request.data['refresh']
        try:
            #get this refresh token from outstanding and invalidate it
            token = RefreshToken(refresh)
            token.blacklist()

            print('ran')
            return Response(status=status.HTTP_200_OK)
        except Exception as e:
            print(e)
            return Response(status=status.HTTP_400_BAD_REQUEST)

我尝试过直接在post方法上设置csrf_exempt但无效,最初使用simplejwt自带的黑名单视图也出现相同错误,因此改用自定义视图。附上中间件列表供排查:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

]

请问为何仅该视图出现此问题,如何解决?

分析与解决

原因

  1. 认证流程触发CSRF检查:当使用IsAuthenticated权限类时,Django的AuthenticationMiddleware会优先尝试通过session认证用户,而CsrfViewMiddleware会对session认证的请求强制CSRF检查——即使给视图加了csrf_exempt,如果认证过程先触发了session相关的CSRF验证,就会抛出错误。
  2. 装饰器优先级冲突:@method_decorator(csrf_exempt, name='dispatch')理论上能豁免视图的CSRF检查,但如果simplejwt的认证逻辑与Django原生session认证存在冲突,或者装饰器没有正确覆盖视图的dispatch方法,可能导致豁免失效。

解决方法

方法一:直接设置APIView的csrf_exempt属性(推荐)

对于DRF的APIView,直接设置类属性csrf_exempt = True比装饰器更可靠,能确保整个视图跳过CSRF检查:

class BlackListToken(APIView):
    permission_classes = (permissions.IsAuthenticated,)
    csrf_exempt = True  # 新增这个属性

    def post(self, request):
        refresh = request.data['refresh']
        try:
            token = RefreshToken(refresh)
            token.blacklist()
            return Response(status=status.HTTP_200_OK)
        except Exception as e:
            print(e)
            return Response(status=status.HTTP_400_BAD_REQUEST)

方法二:调整认证配置,避免session认证干扰

既然使用JWT认证,可在配置中明确DRF默认认证类为JWT,减少session认证的触发概率:

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}

# 可选:如果不需要Django原生session认证,可调整认证后端
AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',  # 保留用于后台管理(按需选择)
    'rest_framework_simplejwt.authentication.JWTAuthentication',
]

方法三:在路由层豁免CSRF检查

直接在urls.py中用csrf_exempt装饰视图的路由,确保请求到达视图前就跳过CSRF验证:

# urls.py
from django.views.decorators.csrf import csrf_exempt
from django.urls import path
from .views import BlackListToken

urlpatterns = [
    path('token/blacklist/', csrf_exempt(BlackListToken.as_view()), name='blacklist-token'),
    # 其他路由...
]

内容的提问来源于stack exchange,提问作者Arham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 07:31:02