You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React集成csurf遇用户切换后CSRF Token无效问题求助

问题解答

一、首次GET请求不带Token为何能通过校验

csurf模块的默认行为是仅对会修改服务器状态的请求(POST/PUT/DELETE等)进行CSRF Token校验,GET、HEAD、OPTIONS这类只读请求默认跳过校验。

当你在/users/current这个GET路由中调用req.csrfToken()时,csurf会自动生成一个Token并将其与当前用户的session绑定存储,然后返回给客户端——整个过程不需要请求头携带Token,因为GET请求本身不在csurf的校验范围内。

二、升级包后出现「invalid csrf token」的原因与修复方案

原因分析

  1. 版本升级后的校验逻辑强化:新版csurf可能对Token与session的绑定关系做了更严格的校验。当用户登录/切换账号时,passport会更新session中的用户身份信息(req.user),此时旧Token关联的是之前的session状态,自然会被判定为无效。
  2. 客户端拦截器叠加问题:你多次调用axiosInstance.interceptors.request.use是在添加新的拦截器,而非替换旧的。比如登录后先添加一个清除Token的拦截器,再添加设置新Token的拦截器,多个拦截器叠加可能导致Token被重复修改,或者旧拦截器残留的Token与新session不匹配。

修复步骤

  1. 服务端调整登录接口:确保/users/login这类登录接口不添加csrfProtection中间件——登录时客户端还未获取到Token,无法携带,且登录请求本身不属于CSRF攻击的典型场景(CSRF利用已登录的session发起请求,而登录时用户还未建立有效session)。
  2. 客户端替换拦截器而非叠加:axios的拦截器可以通过返回的ID移除旧拦截器,避免叠加冲突。示例代码:
    // 全局存储拦截器ID,用于后续移除
    let csrfInterceptor = null;
    
    // 首次获取Token并设置拦截器
    axiosInstance.get("/users/current")
      .then(resJson => {
        // 移除旧拦截器(如果存在)
        if (csrfInterceptor) {
          axiosInstance.interceptors.request.eject(csrfInterceptor);
        }
        // 添加新拦截器
        csrfInterceptor = axiosInstance.interceptors.request.use(config => {
          config.headers["x-csrf-token"] = resJson.data.csrfToken;
          return config;
        });
      });
    
    // 登录后更新Token流程
    axiosInstance.post("/users/login", { username: login.username, password: login.password })
      .then(async () => {
        // 先移除旧拦截器
        if (csrfInterceptor) {
          axiosInstance.interceptors.request.eject(csrfInterceptor);
        }
        // 获取与新session绑定的Token
        const { csrfToken } = await axiosInstance.get("/users/current").then(res => res.data);
        // 设置新的拦截器
        csrfInterceptor = axiosInstance.interceptors.request.use(config => {
          config.headers["x-csrf-token"] = csrfToken;
          return config;
        });
        return csrfToken;
      });
    
  3. 服务端确认csurf配置一致性:显式指定csurf的session键名,确保与passport的session存储键一致,避免因版本升级导致的默认配置变化:
    import csrf from 'csurf';
    // 根据你实际的session存储键调整,比如express-session默认是'session'
    const csrfProtection = csrf({ sessionKey: 'session' });
    

内容的提问来源于stack exchange,提问作者protoplan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 05:18:19