React+Django部署后登录遇CSRF Cookie未设置/验证失败问题求助
React + Django 跨域CSRF认证失败问题解决
问题描述
本地环境下React前端+Django后端运行正常,但前端部署到Heroku(后端本地)或前后端分别部署后,登录POST请求出现以下错误:
- 前端部署Heroku、后端本地时:
Forbidden (CSRF cookie not set.): /login/ - 前后端都部署后:
Forbidden (403) CSRF verification failed. Request aborted.
核心问题分析
- 硬编码域名导致跨域:前端所有请求硬编码
http://localhost:8000,部署后域名不匹配,浏览器拦截Cookie,CSRF Token无法正常获取传递。 - Cookie配置适配不足:生产环境下
SameSite、Secure等Cookie安全配置未正确设置,跨域场景下Cookie无法被携带。 - Token获取逻辑冗余:已有带
@ensure_csrf_cookie的session_view接口,无需单独写getCsrf接口,重复获取易导致Token不一致。
具体修复步骤
1. 前端代码修复
替换硬编码域名,用环境变量适配部署场景
// 定义后端API地址,开发/生产环境自动切换 const API_BASE_URL = process.env.REACT_APP_API_URL || "http://localhost:8000"; // 修改CSRF Token获取逻辑,从Cookie提取更可靠 function getCsrf(){ fetch(`${API_BASE_URL}/session/`, { credentials: "include", }) .then(() => { // 从document.cookie中提取csrftoken const csrfToken = document.cookie.split('; ') .find(row => row.startsWith('csrftoken='))?.split('=')[1] || ''; setCsrf({csrf: csrfToken}); }) .catch((err) => { console.log(err); }) } // 修改登录请求地址 const login = (event) => { event.preventDefault(); setIsLoading(true) fetch(`${API_BASE_URL}/login/`, { method: "POST", headers: { "Content-Type": "application/json", "X-CSRFToken": csrf.csrf, }, credentials: "include", body: JSON.stringify({username: username, password: password}), }) // 其余逻辑保持不变 } // 修改会话校验请求地址 useEffect(() => { setIsLoading(true) fetch(`${API_BASE_URL}/session/`, { credentials: "include", }) .then((res) => res.json()) .then((data) => { if (data.isAuthenticated) { setIsAuthenticated(true) console.log(data) } else { setIsAuthenticated(false) console.log(data) getCsrf() } setIsLoading(false) }) .catch((err) => { console.log(err); }); }, [])
说明:Django默认将CSRF Token存在
csrftokenCookie中,直接从document.cookie提取比响应头更可靠。
2. Django后端配置修复
完善settings.py的Cookie与CORS配置
# settings.py # 生产环境强制开启HTTPS Cookie(必须配合HTTPS部署) CSRF_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True # 跨域场景下SameSite设为None,配合Secure属性使用 CSRF_COOKIE_SAMESITE = 'None' SESSION_COOKIE_SAMESITE = 'None' # 信任所有前端部署域名,替换为实际域名 CSRF_TRUSTED_ORIGINS = [ 'https://your-frontend.herokuapp.com', 'http://localhost:3000', # 其他前端域名 ] # 生产环境建议指定允许的CORS源,而非全量开放 CORS_ALLOWED_ORIGINS = [ 'https://your-frontend.herokuapp.com', 'http://localhost:3000', ] CORS_ALLOW_CREDENTIALS = True CORS_EXPOSE_HEADERS = ['Content-Type', 'X-CSRFToken']
简化CSRF逻辑
删除单独的csrf/接口,复用已有的session_view(该接口带@ensure_csrf_cookie装饰器,会自动设置CSRF Cookie)。
3. 部署注意事项
- 前端环境变量:在Heroku中设置
REACT_APP_API_URL为后端实际部署域名(如https://your-django-backend.herokuapp.com)。 - 后端HTTPS:确保后端使用HTTPS(Heroku默认提供),否则
SecureCookie无法生效。 - Cookie验证:浏览器控制台查看
Application->Cookies,确认csrftoken和sessionidCookie的Domain、Secure属性符合预期。
验证方法
- 部署后检查浏览器控制台是否有跨域错误。
- 确认登录请求的
X-CSRFToken头携带的Token与csrftokenCookie值一致。 - 登录成功后检查
sessionidCookie是否正常设置,会话保持正常。
内容的提问来源于stack exchange,提问作者sash
相关产品推荐
相关产品推荐

