Django Rest框架中CSRF token缺失错误求助(附项目代码)
Django Rest Framework「CSRF Failed: CSRF token missing.」错误解决方案
我现在遇到了Django Rest Framework中的「CSRF Failed: CSRF token missing.」错误,之前的项目从没碰到过这个问题,急需解决办法。以下是我的项目代码:
settings.py
import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent SECRET_KEY = 'django-insecure-n^s54jl394v4!_#n^78&7o-9swqt*ckq1pcyx_g3@vhb$8gct5' DEBUG = True ALLOWED_HOSTS = [] INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', "rest_framework", "accounts", "contents", ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'config.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.SessionAuthentication" ] } WSGI_APPLICATION = 'config.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] LANGUAGE_CODE = 'en-us' STATIC_ROOT = os.path.join("static") TIME_ZONE = 'UTC' USE_I18N = True USE_TZ = True STATIC_URL = 'static/' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
urls.py
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path("accounts/", include("accounts.urls")), path("contents/", include("contents.urls")), ]
accounts.views
from rest_framework.response import Response from rest_framework.generics import CreateAPIView from rest_framework import status from rest_framework.views import APIView from django.contrib.auth.models import User from django.contrib.auth import login, logout, authenticate from accounts.serializers import UserCreationSerializer, UserLoginSerializer class RegisterAPIView(CreateAPIView): model = User queryset = User.objects.all() serializer_class = UserCreationSerializer def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) username = serializer.validated_data.get("username") password = serializer.validated_data.get("password") user = authenticate(username=username, password=password) if user: login(request, user) return Response( data={"msg": "User created successfully and logged in"}, status=status.HTTP_201_CREATED ) return Response( data={"msg": "User Creation process failed"}, status=status.HTTP_400_BAD_REQUEST ) def perform_create(self, serializer): serializer.save() class UserLoginView(APIView): def post(self, request): serializer = UserLoginSerializer(data=request.data) print(request.user.is_authenticated) if serializer.is_valid(): username = serializer.validated_data['username'] password = serializer.validated_data['password'] user = authenticate(username=username, password=password) if user is not None: login(request, user) return Response({'message': 'User logged in successfully'}, status=status.HTTP_200_OK) else: return Response({'message': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class LogoutAPIView(APIView): model = User def get(self, request, *args, **kwargs): logout(request) return Response(data={"msg": "User logged out successfully!"}, status=status.HTTP_200_OK)
accounts.urls
from django.urls import path from accounts import views urlpatterns = [ path("register/", views.RegisterAPIView.as_view(), name="register"), path("login/", views.UserLoginView.as_view(), name="login"), path("logout/", views.LogoutAPIView.as_view(), name="logout") ]
accounts.serializers
from rest_framework import serializers from django.contrib.auth.models import User from django.contrib.auth import authenticate class UserCreationSerializer(serializers.ModelSerializer): class Meta: fields = ["username", "first_name", "last_name", "email", "password"] model = User def save(self, **kwargs): user = self.Meta.model return user.objects.create_user( username=self.validated_data.get("username"), email=self.validated_data.get("email"), password=self.validated_data.get("password"), first_name=self.validated_data.get("first_name"), last_name=self.validated_data.get("last_name"), ) class UserLoginSerializer(serializers.Serializer): username = serializers.CharField(max_length=150) password = serializers.CharField(max_length=128, write_only=True) def validate(self, data): username = data.get('username') password = data.get('password') if username and password: user = authenticate(username=username, password=password) if not user: raise serializers.ValidationError("Invalid username or password.") else: raise serializers.ValidationError("Both username and password are required.") data['user'] = user return data
Postman请求截图:
以上是我能提供的全部代码信息,若问题并非由代码导致,请告知其他可能原因。目前所有环境配置(Google、Postman、Python、编辑器等)均正常工作,项目处于生产环境,恳请提供合适的解决方案。
问题原因与解决方案
1. Postman测试时的临时解决办法
你配置了SessionAuthentication,Django会要求POST/PUT/DELETE等修改性请求携带CSRF token。在Postman中可以这样操作:
- 先发送一个GET请求到任意接口(比如
/accounts/logout/),从响应的Cookie中提取csrftoken值 - 在请求头中添加
X-CSRFToken字段,值为刚才获取的csrftoken - 确保请求携带
sessionidCookie(登录后会自动生成)
2. 生产环境适配方案
根据客户端类型分场景处理:
(1)浏览器端前端(如Vue/React SPA)
- 页面加载时从Cookie读取
csrftoken,在所有非GET请求的请求头中携带X-CSRFToken - 确保
CSRF_COOKIE_HTTPONLY保持默认的False,这样前端可以读取到CSRF token(你的配置符合要求)
(2)非浏览器客户端(如APP、第三方服务)
SessionAuthentication不适合这类场景,建议改用Token认证:
- 在settings.py的REST_FRAMEWORK配置中添加Token认证:
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.SessionAuthentication" # 保留Session用于后台管理 ] }
- 在INSTALLED_APPS中加入
rest_framework.authtoken - 执行
python manage.py migrate生成Token数据表 - 用户登录后返回对应的token,客户端后续请求在请求头携带
Authorization: Token <token值>
3. 代码优化建议
- Logout接口改用POST请求:当前Logout用GET请求不符合REST规范,且GET请求默认不触发CSRF校验(生产环境中存在安全风险),修改为POST:
class LogoutAPIView(APIView): def post(self, request, *args, **kwargs): logout(request) return Response(data={"msg": "User logged out successfully!"}, status=status.HTTP_200_OK)
同时更新accounts.urls中的对应路由,保持请求方法一致。
- 简化Register接口逻辑:创建用户后无需再次调用
authenticate,直接用创建好的用户对象执行login即可:
def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) user = self.perform_create(serializer) login(request, user) return Response( data={"msg": "User created successfully and logged in"}, status=status.HTTP_201_CREATED ) def perform_create(self, serializer): return serializer.save()
其他可能原因
- 跨域问题:如果前后端域名不同,需配置CORS。安装
django-cors-headers,在MIDDLEWARE中添加corsheaders.middleware.CorsMiddleware,并设置CORS_ALLOW_CREDENTIALS = True - Cookie传递异常:确保客户端支持Cookie,Postman中开启「Send cookies」选项
内容的提问来源于stack exchange,提问作者user18519195
相关产品推荐
相关产品推荐

