已在模板中加入CSRF token仍提示缺失?Django AJAX登录问题求助
问题原因
你遇到的CSRF验证失败,核心问题是AJAX请求的数据格式和Django的CSRF验证逻辑不匹配:
- 你用
JSON.stringify()把数据转成了JSON字符串,但Django的request.POST仅处理application/x-www-form-urlencoded(普通表单编码)或multipart/form-data格式的请求体,无法直接解析JSON数据,导致CSRF token无法被识别。 - 即使你把CSRF token放在JSON参数里,Django的CSRF中间件也无法从JSON中读取到这个token进行验证。
解决方案
有两种可行的修正方式,根据你的需求选择:
方式一:保持表单编码格式提交(推荐,无需修改视图)
直接去掉JSON.stringify(),让jQuery自动把数据编码成普通表单格式,和常规表单提交一致:
$(function(){ $(document).on('submit', 'form', function(event){ event.preventDefault(); $.ajax({ type: 'POST', url: 'login', // 直接传递键值对对象,jQuery默认编码为application/x-www-form-urlencoded data: { username: $('input[name=username]').val(), password: $('input[name=password]').val(), csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val() }, success: function(response){ console.log(response); } }); }); });
这种方式下,你的原有视图代码不需要修改,request.POST能正常获取所有参数,CSRF验证也会自动通过。
方式二:使用JSON格式提交(需同步修改视图)
如果必须用JSON格式传递数据,需要同时修改前端和后端:
前端修改
- 设置
contentType: 'application/json'声明请求体格式 - 将CSRF token放到
X-CSRFToken请求头中(Django的CSRF中间件会检查这个请求头)
$(function(){ $(document).on('submit', 'form', function(event){ event.preventDefault(); $.ajax({ type: 'POST', url: 'login', contentType: 'application/json', // 声明请求体为JSON headers: { // 把CSRF token放到请求头 'X-CSRFToken': $('input[name=csrfmiddlewaretoken]').val() }, data: JSON.stringify({ username: $('input[name=username]').val(), password: $('input[name=password]').val() }), success: function(response){ console.log(response); } }); }); });
后端视图修改
因为request.POST无法解析JSON数据,需要手动解析request.body:
import json from django.contrib import auth from django.http import HttpResponse def login(request): if request.method == "POST": # 解析JSON格式的请求体 data = json.loads(request.body) username = data["username"] password = data["password"] user = auth.authenticate(username=username, password=password) if user: auth.login(request, user) return HttpResponse("Successfully logged in!") else: return HttpResponse("Username or Password is incorrect") else: return render(request, "login.html")
补充说明
- 你尝试的手动传递CSRF token到模板的方法是可行的,只要模板中正确渲染
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">,和使用{% csrf_token %}效果完全一致,问题不在token的传递,而是AJAX的提交格式。 - CSRF Cookie值保持不变是正常现象,它的默认有效期是浏览器会话周期,只要浏览器不关闭,Cookie值不会主动变化,这不是导致验证失败的原因。
内容的提问来源于stack exchange,提问作者Ecem
相关产品推荐
相关产品推荐

