React+Django跨域CSRF令牌生成及请求头配置问题求助
解决React + Django应用的CSRF与跨域问题
嘿,我来帮你梳理这两个头疼的问题,结合你生产环境React和Django同服务器部署的情况,咱们一步步解决:
一、搞定CSRF Cookie生成与Token获取的问题
Django自带完整的CSRF防护机制,完全不用你手动生成Cookie,按以下步骤配置就行:
确认CSRF中间件已启用
先检查settings.py里的MIDDLEWARE列表,确保这一行存在(默认是启用的,除非你手动删了):'django.middleware.csrf.CsrfViewMiddleware',让前端稳稳拿到CSRF Token
分两种场景处理:- 生产环境(同服务器部署):React编译后的静态文件放在Django的
static目录,通过Django模板加载。这种情况下,直接在Django的基础模板里把CSRF Token渲染成全局变量最靠谱:
在你的base.html(或类似模板)里加这段代码:
这样React代码里直接用<script> window.csrftoken = '{{ csrf_token }}'; </script>window.csrftoken就好,完全不用从Cookie读,避免首次请求Token为null的问题。 - 开发阶段(跨域调试):需要让Django把CSRF Cookie发送给前端的开发服务器。首先在
settings.py里添加信任的前端域名:
然后用CSRF_TRUSTED_ORIGINS = ['http://localhost:3000'] # 替换成你的React开发服务器地址universal-cookie读取Cookie里的Token:
注意:首次请求前,先让前端访问一个Django的页面(比如首页)或者发一个不带Token的GET请求,Django会自动种下CSRF Cookie,之后就能读到Token了。import Cookies from 'universal-cookie'; const cookies = new Cookies(); // Django默认的CSRF Cookie名是csrftoken window.csrftoken = cookies.get('csrftoken');
- 生产环境(同服务器部署):React编译后的静态文件放在Django的
二、解决跨域请求头的报错问题
你遇到的Request header field X-CSRFToken is not allowed...报错,主要是预请求(OPTIONS)的响应头配置有问题,按以下调整:
修正跨域响应头配置
别用*作为Access-Control-Allow-Origin!当请求带Cookie(CSRF Cookie属于Cookie)时,浏览器不允许用通配符,必须指定具体的前端域名,同时要加上Access-Control-Allow-Credentials: true:response = HttpResponse(json.dumps(software_settings), content_type="application/json") # 开发环境填React服务器地址,生产环境因为同域名,直接写当前域名或者去掉这个头 response['Access-Control-Allow-Origin'] = "http://localhost:3000" response['Access-Control-Allow-Headers'] = "X-Requested-With, X-Prototype-Version, X-CSRF-Token" response['Access-Control-Allow-Methods'] = "POST, GET, OPTIONS" response['Access-Control-Allow-Credentials'] = "true"另外,Django的
CsrfViewMiddleware会自动处理OPTIONS预请求,但如果是自定义视图,记得确保OPTIONS请求能返回200状态码。生产环境可以完全去掉跨域配置
因为生产环境React和Django部署在同一Apache服务器,属于同域名,根本不会有跨域问题,所以生产环境的视图里可以删掉所有Access-Control-*相关的响应头,避免多余配置。
额外的小优化建议
- 把CSRF Token的获取逻辑封装成工具函数,兼顾两种场景:
import Cookies from 'universal-cookie'; function getCsrfToken() { // 优先用模板渲染的全局变量,没有的话从Cookie读 return window.csrftoken || new Cookies().get('csrftoken'); } - 如果用Axios发起请求,可以全局配置CSRF Token,不用每次写
beforeSend:
这样Axios会自动从Cookie取Token并添加到请求头,省掉不少重复代码。import axios from 'axios'; axios.defaults.xsrfHeaderName = 'X-CSRFToken'; axios.defaults.xsrfCookieName = 'csrftoken';
内容的提问来源于stack exchange,提问作者RetroMime
相关产品推荐
相关产品推荐

