React+Django跨域POST请求CSRF Token验证失败问题求助
Django + React 跨域 CSRF 问题解决指南
第一个问题:能否让API直接使用Cookie中的CSRF Token验证请求?
不行。Django的CSRF防护机制设计就是必须同时存在CSRF Cookie和X-CSRFToken请求头,且两者值匹配才会通过验证。这是因为CSRF攻击中,浏览器会自动携带Cookie到目标域名,但攻击者无法伪造自定义请求头(受同源策略限制),仅靠Cookie验证无法有效抵御CSRF攻击,所以Django不支持仅用Cookie完成CSRF验证。
第二个问题:跨域场景下如何让前端获取CSRF Token并放入请求头?
需要从后端Django配置和前端React代码两方面配合处理:
后端Django配置步骤
确保CSRF中间件启用
检查settings.py的INSTALLED_APPS和MIDDLEWARE,确认django.middleware.csrf.CsrfViewMiddleware已存在(默认已启用)。配置CORS支持(必须)
安装django-cors-headers库,然后在settings.py中添加配置:# 安装后添加到中间件(要放在CommonMiddleware之前) MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # 其他中间件... ] # 允许携带跨域Cookie CORS_ALLOW_CREDENTIALS = True # 指定信任的前端域名(不要用*,避免安全风险) CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", # 你的React开发服务器地址 "https://your-frontend-domain.com", # 生产环境前端地址 ] # 告诉Django信任这些域名的CSRF请求 CSRF_TRUSTED_ORIGINS = [ "http://localhost:3000", "https://your-frontend-domain.com", ]调整CSRF Cookie属性
在settings.py中配置Cookie的SameSite和Secure属性,确保跨域场景下浏览器能正常保存并携带:# 开发环境(http)用Lax,生产环境(https)可设为None(需配合Secure=True) CSRF_COOKIE_SAMESITE = 'Lax' # 生产环境启用https时打开,确保Cookie仅通过HTTPS传输 CSRF_COOKIE_SECURE = False # 开发环境设为False,生产设为True # 确保CSRF Cookie可被前端JS访问(默认就是False,不要改成True) CSRF_COOKIE_HTTPONLY = False
前端React代码处理
请求时携带Cookie
无论用fetch还是axios,都要开启携带跨域Cookie的配置:- 用
axios的话,全局配置:import axios from 'axios'; // 全局开启携带Cookie axios.defaults.withCredentials = true; - 用
fetch的话,每个请求添加credentials: 'include':fetch('/api/your-endpoint', { method: 'POST', credentials: 'include', // 其他配置... });
- 用
获取CSRF Token
写一个简单函数从Cookie中提取csrftoken:function getCsrfToken() { const cookieValue = document.cookie .split('; ') .find(row => row.startsWith('csrftoken=')) ?.split('=')[1]; return cookieValue || ''; }自动添加X-CSRFToken请求头
- 用
axios可以添加请求拦截器,自动给需要的请求加头:axios.interceptors.request.use((config) => { // 仅给非GET/HEAD/OPTIONS的请求加CSRF头(Django对这些请求不做CSRF验证) if (!['GET', 'HEAD', 'OPTIONS'].includes(config.method?.toUpperCase())) { const csrfToken = getCsrfToken(); if (csrfToken) { config.headers['X-CSRFToken'] = csrfToken; } } return config; }); - 用
fetch的话,手动在请求头中添加:fetch('/api/your-endpoint', { method: 'POST', credentials: 'include', headers: { 'X-CSRFToken': getCsrfToken(), 'Content-Type': 'application/json', }, body: JSON.stringify(yourData), });
- 用
关键注意事项
- 不要将
CSRF_COOKIE_HTTPONLY设为True,否则前端JS无法读取该Cookie,也就没法添加请求头。 - 开发环境如果用http协议,
CSRF_COOKIE_SAMESITE设为Lax即可;如果是跨不同主域名的场景(比如前端是a.com,后端是b.com),生产环境用https时可以将CSRF_COOKIE_SAMESITE设为None,同时必须开启CSRF_COOKIE_SECURE = True(SameSite=None要求Cookie必须是Secure的)。 - 登录请求也要开启
withCredentials,否则后端设置的CSRF Cookie不会被前端浏览器保存。
内容的提问来源于stack exchange,提问作者gxs629
相关产品推荐
相关产品推荐

