Django 3.0.x CSRF令牌验证失败问题求助
解决Django 3.0.x中CSRF令牌验证失败的问题
看起来你踩了一个很常见的CSRF令牌使用误区,我来帮你拆解问题并给出具体的解决办法:
核心问题:你误解了_get_new_csrf_token()的作用
_get_new_csrf_token()这个方法的作用是生成一个全新的CSRF令牌,但它不会自动将这个新令牌更新到用户的Cookie中。Django的CsrfViewMiddleware验证逻辑是:对比请求头里的X-CSRFToken和请求Cookie中的csrftoken值是否一致——你用新生成的令牌发请求,但Cookie里还是旧的令牌,自然会触发"Forbidden"错误。
具体解决步骤
1. 改用正确的方式获取有效CSRF令牌
不要生成新令牌,直接从当前请求的Cookie中提取已有的有效令牌:
- 后端视图中:用
request.COOKIES.get('csrftoken')获取当前有效的令牌 - 前端AJAX中:通过JS读取Cookie中的令牌,推荐用Django官方文档提供的工具函数:
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; } const csrftoken = getCookie('csrftoken');
2. 修复POSTMAN中的请求配置
你提到request.META里的CSRF_COOKIE和POSTMAN默认Cookie一致,说明POSTMAN自动携带了之前保存的旧Cookie,和你手动设置的新令牌不匹配:
- 清空POSTMAN请求的Cookie(在请求的"Headers"或"Cookies" tab中删除旧的
csrftoken) - 先发送一个GET请求到任意受CSRF保护的页面,从响应Cookie中获取
csrftoken值 - 将这个值同时设置到请求头的
X-CSRFToken和请求Cookie中,再发送POST请求
3. 检查Django配置的关键项
确保你的settings.py中没有破坏CSRF验证的配置:
- 确认
MIDDLEWARE列表中包含'django.middleware.csrf.CsrfViewMiddleware'(默认是启用的,不要注释它) - 检查
CSRF_COOKIE_HTTPONLY是否设为False(默认值)——如果设为True,前端JS无法读取Cookie中的令牌,AJAX请求会失败 - 如果你自定义了
CSRF_COOKIE_NAME,确保请求头的X-CSRFToken对应的值是该自定义Cookie中的内容
4. 正确的AJAX请求示例
用原生JS发送POST请求的完整示例:
const csrftoken = getCookie('csrftoken'); fetch('/your-api-endpoint/', { method: 'POST', headers: { 'X-CSRFToken': csrftoken, 'Content-Type': 'application/json' }, body: JSON.stringify({ /* 你的请求数据 */ }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error));
总结
本质上是你生成的新令牌没有同步到Cookie中,导致Middleware验证时出现"令牌不匹配"的情况。只要改用Cookie中已有的有效令牌,同时确保请求头和Cookie中的令牌一致,就能解决这个问题。
内容的提问来源于stack exchange,提问作者Jatin Suneja
相关产品推荐
相关产品推荐

