React+Django+JWT:如何实现服务端登录状态校验?
问题分析与解决方案
你的核心问题是React组件不能直接返回Promise作为JSX,必须同步渲染内容;同时异步函数的写法可以优化,逻辑更清晰。以下是分步解决的方案:
1. 优化isLoggedIn异步函数
去掉async/await和.then()混用的冗余写法,简化逻辑并增加异常处理:
function saveToken(data) { localStorage.setItem('access_token', data.access); localStorage.setItem('refresh_token', data.refresh); return true; } async function isLoggedIn() { const accessToken = localStorage.getItem('access_token'); const refreshToken = localStorage.getItem('refresh_token'); // 本地无token直接判定未登录 if (!accessToken || !refreshToken) return false; try { // 先用access token校验 await axios.post('api/getuser/', {}, { headers: { Authorization: `Bearer ${accessToken}` } }); return true; } catch (accessErr) { // access token失效,尝试刷新 try { const refreshRes = await axios.post('api/token/refresh/', { refresh: refreshToken }); saveToken(refreshRes.data); return true; } catch (refreshErr) { // 刷新失败,清除本地无效token localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); return false; } } }
2. 重构React组件,用状态管理异步结果
React组件必须同步返回JSX,所以需要用useState存储授权状态,useEffect触发异步校验,同时处理加载状态:
import { useState, useEffect } from 'react'; import { Navigate, useLocation, useOutlet } from 'react-router-dom'; const ComponentMainArea = () => { const location = useLocation(); const element = useOutlet(); // null表示校验中,true/false表示授权状态 const [isAuthenticated, setIsAuthenticated] = useState(null); useEffect(() => { const checkAuth = async () => { const authStatus = await isLoggedIn(); setIsAuthenticated(authStatus); }; checkAuth(); }, []); // 校验中显示加载提示,避免组件渲染异常 if (isAuthenticated === null) { return <div>加载中...</div>; } // 未授权则跳转登录页,记录当前路径方便登录后返回 if (!isAuthenticated) { return <Navigate to="/proxy/8000/login" state={{ from: location.pathname }} />; } // 授权通过,渲染页面内容 return ( <div className='mainarea'> <AnimatePresence mode='wait' initial={true}> {element && React.cloneElement(element, { key: location.pathname })} </AnimatePresence> </div> ); };
3. 进阶优化建议
- 全局状态管理:把授权状态放到React Context或Redux中,避免每个组件重复调用校验接口,提升性能。
- 路由守卫封装:可以封装一个
ProtectedRoute组件,统一处理所有需要授权的路由,减少代码冗余。 - 请求拦截器:在Axios中添加请求拦截器,自动在请求头携带token,无需每个请求手动设置。
内容的提问来源于stack exchange,提问作者Maxim Quitom
相关产品推荐
相关产品推荐

