Django项目提交表单出现403 Forbidden错误(CSRF令牌问题)
解决Django中JS提交表单的CSRF 403错误
核心问题分析
你遇到的问题核心在于CSRF令牌的获取与传递逻辑错误,尤其是JS动态生成HTML场景下,模板标签未被正确解析、令牌未与Cookie同步,以及fetch请求未携带凭证这几个关键点。
分步解决方案
1. 正确获取CSRF令牌(避免模板标签未解析)
由于你用JS生成HTML,直接在JS代码里写{{ csrf_token }}不会被Django模板引擎解析,拿到的只是字符串而非实际令牌。正确做法是:
- 在Django渲染的主HTML文件(比如
base.html)中,提前将令牌存入全局变量:
主模板会被Django解析,这里的<script> window.csrfToken = '{{ csrf_token }}'; </script>{{ csrf_token }}会自动替换为当前会话的有效令牌。
2. 动态生成表单时添加有效令牌字段
不要硬编码令牌值,而是用全局变量动态插入隐藏字段:
// 假设你正在用JS生成表单 const form = document.createElement('form'); form.addEventListener('submit', apiSendDataUser); // 添加CSRF隐藏字段 const csrfInput = document.createElement('input'); csrfInput.type = 'hidden'; csrfInput.name = 'csrfmiddlewaretoken'; csrfInput.value = window.csrfToken; // 使用全局变量的有效令牌 form.appendChild(csrfInput); // 添加其他表单字段(邮箱、用户名、密码等) // ...
3. 调整fetch请求配置(确保携带凭证)
fetch默认不会携带Cookie,而Django的CSRF验证需要比对请求中的令牌与Cookie中的令牌是否一致,因此必须添加credentials: 'include':
const apiSendDataUser = (event) => { event.preventDefault(); const formData = new FormData(event.target); fetch('https://127.0.0.1:8000/myProject/post_user',{ method: 'POST', body: formData, credentials: 'include' // 关键:携带Cookie用于CSRF验证 }) .then(response => { if (response.ok) { return response.json(); } else { throw new Error('Error: ' + response.status); } }) .then(data => { console.log(data); }) .catch(error => { console.error(error); }); };
说明:如果表单中已经正确包含
csrfmiddlewaretoken字段,FormData会自动携带该参数,无需再在headers中手动添加X-CSRFToken。
4. 备选方案:从Cookie中直接获取令牌
如果动态生成表单的场景复杂,也可以直接从Cookie中提取CSRF令牌,无需依赖表单字段:
// 工具函数:从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; } // 修改fetch请求逻辑 const apiSendDataUser = (event) => { event.preventDefault(); const csrfToken = getCookie('csrftoken'); const formData = new FormData(event.target); fetch('https://127.0.0.1:8000/myProject/post_user',{ method: 'POST', body: formData, headers: { 'X-CSRFToken': csrfToken }, credentials: 'include' }) .then(response => { // ... 后续逻辑不变 }) // ... };
5. 后端配置检查
确保你的Django项目settings.py中启用了CSRF中间件:
MIDDLEWARE = [ # ... 其他中间件 'django.middleware.csrf.CsrfViewMiddleware', # ... ]
如果是跨域场景(比如前端运行在8080端口,后端在8000),需安装并配置django-cors-headers:
- 安装:
pip install django-cors-headers - 添加到
INSTALLED_APPS和MIDDLEWARE - 设置:
CORS_ALLOW_CREDENTIALS = True CORS_ORIGIN_WHITELIST = [ 'http://localhost:8080', # 你的前端域名/端口 ]
内容的提问来源于stack exchange,提问作者Daniel N
相关产品推荐
相关产品推荐

