根本原因是请求未携带有效CSRF token或token被破坏,需确保CsrfViewMiddleware启用、视图未禁用CSRF、模板用render()渲染以提供csrf_token上下文,且Cookie与表单字段值一致。

为什么 Django 表单提交总报 403 Forbidden 且提示 CSRF verification failed?
根本原因不是模板漏写了 {% csrf_token %},而是请求未携带有效 CSRF token,或 token 在传输/存储环节被破坏。Django 默认对所有非安全方法(POST、PUT、DELETE)强制校验,且校验逻辑严格依赖两个值的一致性:csrftoken Cookie 和表单中 csrfmiddlewaretoken 字段值。
在模板中正确插入 {% csrf_token %} 的前提条件
这个标签本身只是生成一个隐藏输入框,它不会“自动修复”问题。必须确保以下三点同时满足:
- Django 的
django.middleware.csrf.CsrfViewMiddleware已启用(默认在MIDDLEWARE列表中) - 视图函数/类没有显式禁用 CSRF(例如没加
@csrf_exempt装饰器) - 模板渲染时使用的是
RequestContext(Django 2.0+ 中由render()自动处理,但若用HttpResponse+loader.render_to_string()就可能遗漏)
错误示例:return HttpResponse(loader.render_to_string('form.html', {})) —— 此时 {% csrf_token %} 会生成空字段,因为上下文里没有 csrf_token 变量。
CSRF token 不生效的常见埋点场景
即使写了 {% csrf_token %},也可能因以下原因失败:
立即学习“Python免费学习笔记(深入)”;
- 前端用 AJAX 提交时,没从
Cookie或<meta name="csrf-token">中读取 token 并设为请求头X-CSRFToken - 用户禁用了 Cookie,而你又没配置
CSRF_USE_SESSIONS = True - 反向代理(如 Nginx)清除了
Set-Cookie响应头,或未透传Cookie请求头 - 开发环境用了
http://localhost:8000,但前端资源从http://127.0.0.1:8000加载 —— 域名不一致导致 Cookie 不发送
验证方式:打开浏览器开发者工具 → Application → Cookies,确认存在 csrftoken;再看表单 HTML 源码,确认 <input type="hidden" name="csrfmiddlewaretoken" value="..."> 的 value 与 Cookie 中的值一致(注意:Django 会对 Cookie 值做签名,所以二者不完全相同,但解码后原始 token 应一致)。
调试和绕过 CSRF 的临时手段(仅限开发)
生产环境绝不可关闭 CSRF,但本地快速验证逻辑时可临时调整:
- 给特定视图加
@csrf_exempt(仅用于 API 测试,切勿提交到 git) - 在
settings.py中设CSRF_COOKIE_SECURE = False和CSRF_COOKIE_HTTPONLY = False(否则 HTTPS 环境下 Cookie 不会被 JS 读取) - 用
curl -v -X POST -H "X-CSRFToken: $(grep csrftoken cookies.txt | awk '{print $7}')" --data "name=test" http://localhost:8000/submit/手动构造请求验证流程
真正稳定的解法永远是让 Cookie 和表单字段协同工作——而不是删掉 {% csrf_token %} 或关掉中间件。最常被忽略的是:AJAX 请求必须手动提取并携带 token,Django 不会自动注入到 fetch/fetch-XHR 的 headers 中。


















