如何让redux-auth-wrapper等待会话校验完成再执行路由拦截?
解决redux-auth-wrapper提前拦截路由的问题
我明白你的痛点——刷新受保护路由时,redux-auth-wrapper的校验逻辑跑在cookie验证和用户状态更新之前,直接把你踢回首页了。不用急,咱们可以通过添加加载状态让auth wrapper等待会话校验完成,下面是具体实现步骤:
1. 在Redux用户状态中添加加载标记
首先在你的user reducer里新增一个isLoading状态,用来标记会话校验是否完成:
// 示例user reducer初始状态 const initialState = { isAuthenticated: false, isAdmin: false, isLoading: true // 初始设为true,因为页面加载时正在校验会话 };
然后在登录、登出以及会话校验的action处理中,同步更新这个状态:
- 开始校验会话时,设置
isLoading: true - 校验完成(无论登录成功/失败),设置
isLoading: false
2. 修改auth.js的认证选择器逻辑
让redux-auth-wrapper在加载状态下不触发跳转,等待状态稳定后再做真实校验:
export const UserIsAdmin = connectedRouterRedirect({ wrapperDisplayName: 'UserIsAdmin', AuthenticatingComponent: Spinner, // 取消注释,显示加载状态(可选) redirectPath: (state, ownProps) => locationHelper.getRedirectQueryParam(ownProps) || '/', allowRedirectBack: true, authenticatedSelector: state => { // 加载中时返回true,阻止跳转 if (state.user.isLoading) return true; // 加载完成后判断真实权限 return state.user.isAuthenticated && state.user.isAdmin; } }); export const UserIsAuthenticated = connectedRouterRedirect({ wrapperDisplayName: 'UserIsAuthenticated', AuthenticatingComponent: Spinner, redirectPath: (state, ownProps) => locationHelper.getRedirectQueryParam(ownProps) || '/', allowRedirectBack: true, authenticatedSelector: state => { if (state.user.isLoading) return true; return state.user.isAuthenticated; } }); export const UserIsNotAuthenticated = connectedRouterRedirect({ wrapperDisplayName: 'UserIsNotAuthenticated', AuthenticatingComponent: Spinner, redirectPath: (state, ownProps) => locationHelper.getRedirectQueryParam(ownProps) || '/', allowRedirectBack: true, authenticatedSelector: state => { if (state.user.isLoading) return true; return !state.user.isAuthenticated; } });
3. 调整MainRoutes的会话校验逻辑
确保isLoading状态正确同步,等待异步登录操作完成后再关闭加载状态:
const MainRoutes = ( { cookies } ) => { const { isAuthenticated, isLoading } = useSelector( state => state.user ); const dispatch = useDispatch(); const login = () => dispatch( loginAction() ); // 假设loginAction是异步action(如redux-thunk) const logout = () => dispatch( logoutAction() ); const setLoading = (status) => dispatch({ type: 'SET_LOADING', payload: status }); // 新增设置加载状态的action useEffect(() => { const checkSession = async () => { setLoading(true); try { const cookie = cookies.get('token'); if( cookie && cookie.trim() !== '' ) { axiosClient.defaults.headers.Authorization = `Bearer ${ cookie }`; await login(); // 等待登录请求完成,确保用户状态更新 } else { logout(); } } catch (err) { logout(); console.error('会话校验失败:', err); } finally { setLoading(false); // 无论成功失败,都结束加载状态 } }; if (!isAuthenticated && isLoading) { checkSession(); } else if (isAuthenticated) { setLoading(false); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [ cookies, isAuthenticated, dispatch ]); // ... 原有路由代码不变 } export default withRouter(withCookies(MainRoutes));
原理说明
通过isLoading状态,我们让redux-auth-wrapper在会话校验完成前保持"等待"状态,不会立即触发跳转。当校验完成、用户状态更新后,auth wrapper会重新执行认证逻辑,此时就能拿到正确的isAuthenticated和isAdmin状态,从而决定是否允许访问目标路由。
内容的提问来源于stack exchange,提问作者Fran M
相关产品推荐
相关产品推荐

