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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 09:27:53