Django与AJAX交互时CSRF Token无效问题求助
解决Django跨域AJAX请求的CSRF Token错误问题
首先咱们明确核心问题:你的请求是跨域场景(React在3000端口,Django在8000端口),虽然禁用了Chrome的跨源检查,但这会导致Cookie和Token的处理逻辑异常,再加上当前请求头里的X-CSRFToken和Cookie中的csrftoken值不一致,直接触发了Django的CSRF验证失败。下面是具体的解决步骤:
1. 用正规CORS配置替代浏览器跨源检查
禁用浏览器跨源检查只是临时调试方案,正规做法是让Django支持跨域请求并允许Cookie传递:
- 先安装
django-cors-headers依赖:pip install django-cors-headers - 在
settings.py中添加配置:INSTALLED_APPS = [ # ... 其他已安装应用 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', # 必须放在CsrfViewMiddleware之前 'django.middleware.common.CommonMiddleware', # ... 其他中间件 'django.middleware.csrf.CsrfViewMiddleware', # ... ] # 允许你的React应用域名 CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", ] # 允许跨域请求携带Cookie(关键配置) CORS_ALLOW_CREDENTIALS = True
2. 确保CSRF Token的获取与发送完全一致
你当前的核心矛盾是请求头Token和Cookie Token不匹配,这是因为前端没有正确读取最新的Cookie Token:
- 先给用来获取CSRF Token的初始GET视图添加
@ensure_csrf_cookie装饰器,确保Django能给前端设置CSRF Cookie:from django.views.decorators.csrf import ensure_csrf_cookie from django.http import JsonResponse @ensure_csrf_cookie def init_csrf(request): return JsonResponse({"status": "ready"}) - 修改前端AJAX的Token获取逻辑,直接从Cookie中读取当前有效的
csrftoken:// 封装Cookie读取函数 function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } // AJAX请求配置 $.ajax({ url: "/login/", method: "POST", data: {username: "xxx", password: "xxx"}, beforeSend: function (xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { const csrftoken = getCookie('csrftoken'); xhr.setRequestHeader("X-CSRFToken", csrftoken); } }, // 跨域必须开启这个,否则Cookie不会被发送到后端 xhrFields: { withCredentials: true }, crossDomain: true, success: function(res) { console.log(res); } });
3. 验证请求的Token一致性
修改完成后,重新发起请求,检查请求头:
- 确保
Cookie字段中包含csrftoken,且X-CSRFToken的值和它完全相同 - 确认请求头的
Origin是http://localhost:3000,且已在Django的CORS_ALLOWED_ORIGINS中配置
4. 完善Django登录视图的异常处理
你的登录视图目前没有处理认证失败的情况,建议补充完整避免500错误:
from django.http import JsonResponse from django.contrib.auth import authenticate def login(request, *args, **kwargs): if request.method != 'POST': return JsonResponse({"error": "Method not allowed"}, status=405) username = request.POST.get('username') password = request.POST.get('password') user = authenticate(request, username=username, password=password) if user is not None: return JsonResponse({"user_id": user.id}, status=200) else: return JsonResponse({"error": "Invalid username or password"}, status=401)
最后记得重启Django服务,清除浏览器缓存和Cookie后重新测试,应该就能解决CSRF Token不匹配的问题了。
内容的提问来源于stack exchange,提问作者RetroMime
相关产品推荐
相关产品推荐

