Django REST同时使用Session与Token认证时CSRF Token异常问题咨询
嘿,这个问题我太熟了——我之前帮好几个做跨端认证的团队踩过这个坑!本质上是你的服务端把Session认证的CSRF防护逻辑,不小心套到Token认证的路由上了,导致两种认证的状态互相干扰。咱们一步步拆解问题,再给你落地的解决方案:
冲突的根源到底是什么?
当你用Session登录第一个用户时,服务端会给浏览器种下sessionid Cookie,同时CSRF防护中间件会自动激活(毕竟Session是有状态的,必须防跨站请求伪造)。这时候你再发起Token登录请求,服务端检测到请求里带着之前的Session Cookie,就会默认触发CSRF校验,但Token登录的请求通常不会携带CSRF Token(因为前端没处理,或者Token认证本身不需要这层防护),自然就报错了。退出登录后Session Cookie被清空,CSRF校验的触发条件消失,问题也就没了。
具体解决方案(按优先级排序)
1. 给两种认证路由做精准隔离,控制CSRF校验范围
这是最根本的解决办法:把Session相关的路由和Token相关的路由彻底分开,只给Session路由套CSRF防护,Token路由完全跳过。
举个Node.js Express的例子:
const express = require('express'); const csrf = require('csurf'); const csrfProtection = csrf({ cookie: true }); const app = express(); // Session认证相关路由:必须过CSRF校验 app.use('/session/login', csrfProtection, sessionLoginHandler); app.use('/session/logout', csrfProtection, sessionLogoutHandler); app.use('/api/session', csrfProtection, sessionAuthMiddleware, sessionApiRoutes); // Token认证相关路由:完全跳过CSRF校验 app.use('/token/login', tokenLoginHandler); app.use('/api/token', tokenAuthMiddleware, tokenApiRoutes);
如果是Django的话,可以通过自定义中间件来跳过特定路由的CSRF校验:
from django.middleware.csrf import CsrfViewMiddleware class SelectiveCSRFMiddleware(CsrfViewMiddleware): def process_view(self, request, view_func, view_args, view_kwargs): # 跳过Token相关路由的CSRF校验 if request.path.startswith('/token/login/') or request.path.startswith('/api/token/'): return None return super().process_view(request, view_func, view_args, view_kwargs)
2. 调整认证中间件的优先级:Token优先于Session
让服务端先检查请求里有没有Token(比如Authorization: Bearer <your-token>),如果有就直接走Token认证流程,完全忽略Session和CSRF校验;只有当请求里没有Token时,再走Session认证和对应的CSRF防护。
这样即使请求里带着Session Cookie,只要有合法的Token,就不会触发CSRF校验,从根源上避免冲突。
3. 前端配合:切换认证方式时清理Session状态
前端层面可以提前规避这个问题:当用户从Session登录切换到Token登录时,先调用Session登出接口(或者直接设置Session Cookie过期),确保请求Token登录时,浏览器不会携带旧的Session Cookie。
比如用Axios发起Token登录请求时,可以设置不携带Cookie:
axios.post('/token/login', { username, password }, { credentials: 'omit' // 不携带任何Cookie,包括Session Cookie });
4. 极端场景处理:允许同一用户同时用两种认证
如果你的业务允许同一用户同时在Web端用Session、移动端用Token,那要确保服务端的用户状态完全隔离:
- Session的用户信息存在Session存储里
- Token的用户信息存在Token的Payload里
绝对不要让两种认证方式的用户状态互相覆盖或干扰。同时保持CSRF校验只绑定在Session路由上,Token路由完全独立。
这个问题对前端上线后的影响
很明确:如果不解决,用户在Web端用Session登录后,再用同一个浏览器打开你的H5页面走Token登录,就会触发CSRF报错,直接阻断登录流程,体验极差。所以必须在前端上线前搞定这个问题。
内容的提问来源于stack exchange,提问作者Zygro

