Flask-WTF集成后CSRF Token始终为空问题求助(Jinja/JavaScript环境)
问题根因
Jinja2 模板语法仅会在 Flask 调用 render_template() 方法渲染的 HTML 模板文件中被解析执行,存放在静态目录(默认是static文件夹)下的独立 JS 文件不会经过 Jinja 渲染处理,因此你写在 JS 文件里的{{ csrf_token() }}会被直接当做普通字符串返回,不会执行对应的方法生成令牌。
解决方案
下面是3种常用的适配方案,按通用性排序:
方案1:通过HTML meta标签传递(最推荐)
- 在你渲染的 HTML 模板的
<head>标签内添加meta节点,这里的{{ csrf_token() }}会在渲染HTML时被替换为真实令牌:
<meta name="csrf-token" content="{{ csrf_token() }}">
- 在任意JS文件中读取该meta标签的内容即可获取令牌:
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
- 发起请求时携带令牌即可,以fetch请求为例,将令牌放到
X-CSRFToken请求头中:
fetch('/your-api-path', { method: 'POST', headers: { 'X-CSRFToken': csrfToken, 'Content-Type': 'application/json' }, body: JSON.stringify(yourData) })
方案2:直接读取CSRF Cookie
Flask-WTF 的 CSRF 模块默认会给用户种下名为csrf_token的 Cookie,且该 Cookie 默认不开启HttpOnly,允许JS读取,你可以直接用JS读取该Cookie获取令牌:
function getCookie(name) { let value = "; " + document.cookie; let parts = value.split("; " + name + "="); if (parts.length === 2) return parts.pop().split(";").shift(); } const csrfToken = getCookie('csrf_token');
方案3:将JS逻辑内联到HTML模板中
如果你的JS代码量不大,可以直接把用到csrf_token()的逻辑写在HTML模板的<script>标签内,内联在模板中的JS代码里的Jinja语法会被正常解析。
注意事项
- 如果选择通过请求体携带令牌,只需将参数名设为
csrf_token即可被Flask-WTF正常识别,无需修改请求头。 - 不要尝试将静态目录下的JS文件配置为走Jinja渲染,会带来不必要的性能损耗和安全风险。
内容的提问来源于stack exchange,提问作者Vijo
相关产品推荐
相关产品推荐

