无用户登录的Django站点API请求如何传递CSRF令牌
核心方案说明
首先你要先明确:你当前写的Authorization头硬编码令牌校验的逻辑,和Django原生CSRF令牌机制是两套完全独立的鉴权逻辑,而且你没有搭建用户登录体系的前提下,用CSRF机制根本实现不了「仅本人可访问API」的效果——CSRF的设计目的是防跨站伪造请求,前提是站点有用户登录态、需要区分不同已登录用户的操作权限,无登录态时所有能打开你页面的访客都能拿到页面里嵌入的CSRF令牌,照样可以调用你的接口,完全达不到权限控制的目的。
关于令牌生成策略的选择
分两种场景选就行:
- 如果你的核心需求是仅你自己能调用接口、不对普通访客开放,完全没必要用CSRF机制。直接一次性生成高复杂度的固定令牌重复使用即可:
- 用
secrets.token_urlsafe(32)生成一个长度足够的随机字符串,存到Django配置文件里当常量 - 接口里直接比对请求头里的
Authorization值和这个常量是否一致,校验通过才放行 - 不需要每次运行脚本重新生成令牌,只要令牌不泄露,固定使用的安全性完全足够,反复重生成反而需要你同步修改前端调用的令牌值,纯增加不必要的工作量
- 用
- 如果你只是想学习/必须接入Django CSRF校验逻辑,CSRF令牌不需要你手动生成,Django的CSRF中间件会在页面渲染时自动生成、定期轮换,你直接从请求对象里取了传给前端就行。
额外提醒:你贴的示例代码有笔误,
requests.headers多写了一个s,DRF视图里的请求对象是单数形式,正确写法是request.headers,否则运行时会抛出NameError。
CSRF令牌的前端获取与接口配置方法
如果你坚持要接入CSRF校验,按下面步骤配置即可:
- 类视图传递令牌到模板
在类视图的get_context_data方法中调用Django提供的get_token方法拿到CSRF令牌,注入模板上下文:
from django.middleware.csrf import get_token from django.views.generic import TemplateView class PaymentPageView(TemplateView): template_name = "payment.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 把CSRF令牌传到模板上下文 context["csrf_token"] = get_token(self.request) return context
- HTML中嵌入令牌供前端调用
你可以直接把令牌渲染到JS变量,或者存在meta标签里方便读取:
<!-- 存到meta标签 --> <meta name="csrf-token" content="{{ csrf_token }}"> <script> // 或者直接渲染为JS常量 const CSRF_TOKEN = "{{ csrf_token|escapejs }}"; </script>
- 前端请求携带CSRF令牌
发POST请求时,把令牌放到X-CSRFToken请求头里即可,以fetch请求为例:
fetch("/api/payment/", { method: "POST", headers: { "X-CSRFToken": document.querySelector('meta[name="csrf-token"]').content, "Content-Type": "application/json", // 如果你同时用固定令牌鉴权,在这里加Authorization头 // "Authorization": "你提前生成的固定访问令牌" }, body: JSON.stringify({/* 你的请求参数 */}) })
- DRF接口的CSRF配置
如果你没有修改DRF的默认鉴权类,只要请求携带了正确的X-CSRFToken头、浏览器对应域名下存在csrftokenCookie,DRF会自动完成CSRF校验,不需要你在接口代码里额外写判断逻辑。如果你的接口加了@csrf_exempt装饰器豁免了CSRF校验,把装饰器去掉即可。
内容的提问来源于stack exchange,提问作者bernardo
相关产品推荐
相关产品推荐

