django-rest-auth登出CSRF Failed,React+Redux+DRF如何解决?
报错根因
- 登出请求的
X-CSRFToken头传值逻辑错误:你现在把登录后存在localStorage里、用于API身份认证的rest-auth返回令牌(也就是登录接口返回的res.data.key),当成Django要求的CSRF校验值传递,两个值的生成逻辑、作用域完全不同,自然无法通过CSRF校验。 - 配套配置不匹配:后端当前仅开启了
SessionAuthentication,既没有配置TokenAuthentication来识别你本地存的API令牌,跨域场景下也没有配置允许前端携带Cookie,导致前端根本读不到存在Cookie里的合法CSRF值。
修复操作步骤
- 修正前端CSRF值的读取逻辑
CSRF token由Django设置在当前域的Cookie中,字段名为csrftoken,需要单独从Cookie中读取,不能直接复用API认证token。可以加个简单的Cookie读取工具:
登出时取const getCookieValue = (cookieName) => { let targetValue = null if (document.cookie) { const allCookies = document.cookie.split(';') for (const item of allCookies) { const trimmedItem = item.trim() if (trimmedItem.startsWith(`${cookieName}=`)) { targetValue = decodeURIComponent(trimmedItem.substring(cookieName.length + 1)) break } } } return targetValue }getCookieValue('csrftoken')的值填到X-CSRFToken请求头。 - 补全fetch请求的Cookie携带配置
因为前后端跑在不同端口(前端默认3000、后端默认8000),属于跨域场景,fetch请求必须加credentials: 'include'配置,否则浏览器不会把后端设置的Session Cookie、CSRF Cookie带到请求里,既读不到合法CSRF值,也没法维持登录Session。修正后的请求配置参考:const requestOptions = { method: "POST", headers: { "Content-Type": "application/json", 'X-CSRFToken': getCookieValue('csrftoken'), }, credentials: 'include' }; - 调整后端DRF配置和实际认证逻辑匹配
因为你现在前端是把rest-auth返回的API token存在localStorage做身份识别的,需要把TokenAuthentication加到DRF的认证类列表里,同时把接口权限从AllowAny调整为IsAuthenticated,不然登出接口识别不到登录用户,也没法触发登出逻辑:REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ), } - 补全CORS跨域配置
用django-cors-headers做跨域支持时,需要开启CORS_ALLOW_CREDENTIALS = True,同时把允许的源明确设置为前端实际运行的地址(比如http://127.0.0.1:3000),不要用*通配符,否则跨域场景下带凭证的请求会被浏览器拦截。
容易混淆的细节
- 两个token的作用完全独立:CSRF token是做跨站请求伪造防护的随机值,存在Cookie中,和同源校验逻辑绑定;API身份令牌是做用户识别的长期/短期凭证,存在本地存储中,二者没有互换关系。
- 只要接口开启了
SessionAuthentication,POST类请求的CSRF校验就是强制的,哪怕接口权限设置为AllowAny,也必须带正确的CSRF头才能通过校验。
内容的提问来源于stack exchange,提问作者adel bouakaz
相关产品推荐
相关产品推荐

