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

DRF与ReactJS间httpOnly认证状态刷新丢失问题求助

问题排查与修复方案

核心问题分析

页面刷新后认证状态丢失,本质是两个关键问题:

  • React请求未携带认证Cookie到DRF后端,导致check_auth_status接口返回401
  • Redux状态在页面刷新时被重置,且verifyAuth请求完成前,ProtectedRoute已判定未认证并跳转

具体修复步骤

1. 修复Axios配置,确保请求携带Cookie

React项目中api/axios.js必须开启withCredentials,否则浏览器不会把DRF设置的access_token Cookie发送给后端:

// api/axios.js
import axios from 'axios';

const api = axios.create({
  baseURL: 'http://localhost:8000/', // 你的DRF服务地址
  withCredentials: true, // 关键:开启携带Cookie
});

export default api;

2. 统一DRF的Cookie配置,适配本地开发环境

你的DRF Settings中存在Cookie属性不一致的问题,调整如下:

# settings.py
# CORS设置保持不变
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = [
    "http://localhost:3000",
]

# CSRF设置:本地开发用HTTP,所以CSRF_COOKIE_SECURE设为False
CSRF_COOKIE_SECURE = False  # 生产环境部署HTTPS时改回True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = "Lax"  # 和access_token的samesite属性保持一致

# 确保DRF启用JWT认证(如果未配置)
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
}

同时调整views.py中access_token的secure属性,和CSRF Cookie保持一致:

# views.py
# 在CookieTokenObtainPairView和CookieTokenRefreshView的set_cookie方法中
response.set_cookie(
    "access_token",
    response.data["access"],
    httponly=True,
    secure=False,  # 本地开发设为False,生产环境改True
    samesite="Lax",
)

3. 优化Redux与ProtectedRoute逻辑,避免过早跳转

页面刷新时,verifyAuth是异步请求,ProtectedRoute会先读取初始的isAuthenticated: false并跳转登录页。需要添加加载状态,等待认证请求完成:

修改authSlice.js,添加加载状态:

export const authSlice = createSlice({
  name: "auth",
  initialState: {
    isAuthenticated: false,
    isLoading: true, // 新增加载状态标记
  },
  reducers: {
    // ... 保留原有reducer逻辑
  },
  extraReducers: (builder) => {
    builder
      .addCase(verifyAuth.pending, (state) => {
        state.isLoading = true; // 请求开始时标记加载中
      })
      .addCase(verifyAuth.fulfilled, (state) => {
        state.isAuthenticated = true;
        state.isLoading = false;
      })
      .addCase(verifyAuth.rejected, (state) => {
        state.isAuthenticated = false;
        state.isLoading = false;
      });
  },
});

修改ProtectedRoute.js,等待加载完成再判断:

const ProtectedRoute = ({ children }) => {
  const { isAuthenticated, isLoading } = useSelector((state) => state.auth);
  const location = useLocation();

  // 加载中时显示加载组件(可替换为你的自定义加载UI)
  if (isLoading) {
    return <div>加载中...</div>;
  }

  if (!isAuthenticated) {
    return <Navigate to="/login" state={{ from: location }} replace />;
  }

  return children;
};

export default ProtectedRoute;

4. 添加Token自动刷新逻辑(可选)

如果access_token过期,可通过Axios拦截器自动调用refresh接口更新Cookie:

// api/axios.js
api.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    // 401且未重试过,调用refresh接口
    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      try {
        await api.post('/api/token/refresh/');
        return api(originalRequest); // 重试原请求
      } catch (refreshError) {
        // 刷新失败,跳转到登录页
        window.location.href = '/login';
        return Promise.reject(refreshError);
      }
    }
    return Promise.reject(error);
  }
);

验证步骤

  1. 登录成功后,打开浏览器开发者工具(Application标签),确认access_token Cookie已存在
  2. 刷新页面,查看Network请求,确认check_auth_status请求携带了Cookie且返回200
  3. 页面不再跳转到登录页,Redux状态中isAuthenticated变为true

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 05:05:21