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

ReactJS用户登出后点击浏览器返回按钮仍可访问仪表盘如何解决

问题根因
  • 私有路由ConfigRoute只判断了加载状态,没有校验用户登录状态,加载完成后不管用户有没有登录都会直接渲染受保护组件
  • 登出逻辑只清理了本地存储,没有主动跳转到登录页,浏览器历史栈还保留了仪表盘页面的访问记录
  • checkLoginAction仅处理了登录态有效时跳转到仪表盘的逻辑,没有处理登录态失效时跳转到登录页的分支
  • 未配置页面缓存规则,浏览器可能直接读取缓存的历史页面,不触发路由校验
修复步骤

1. 补全checkLoginAction的未登录分支逻辑

export const checkLoginAction = history => dispatch => {
  //! Loading
  dispatchLoading(dispatch, CHECK_LOGIN_ACTION);
  const user = JSON.parse(window.localStorage.getItem('user'));

  if (user) {
    firebase
      .database()
      .ref(`users/${user.uid}`)
      .once('value')
      .then(snapshot => {
        if (snapshot.val()) {
          window.localStorage.setItem('user', JSON.stringify(snapshot.val()));
          dispatchSuccess(dispatch, CHECK_LOGIN_ACTION, snapshot.val());
        } else {
          // 用户不存在,清空存储跳登录
          window.localStorage.removeItem('user');
          dispatchSuccess(dispatch, CHECK_LOGIN_ACTION, null);
          history.replace('/auth/login');
        }
      })
      .catch(() => {
        // 请求失败,清空存储跳登录
        window.localStorage.removeItem('user');
        dispatchSuccess(dispatch, CHECK_LOGIN_ACTION, null);
        history.replace('/auth/login');
      })
  } else {
    // 本地无用户信息,直接跳登录
    dispatchSuccess(dispatch, CHECK_LOGIN_ACTION, null);
    history.replace('/auth/login');
  }
};

2. 补全私有路由的登录拦截逻辑

function ConfigRoute({ component: Component, dispatch, checkLoginLoading, checkLoginResult, ...rest }) {
  const history = useHistory();

  useEffect(() => {
    dispatch(checkLoginAction(history));
  }, [dispatch, history]);

  return (
    <Route
      {...rest}
      render={(props) => {
        if (checkLoginLoading) {
          return <LoadingIndicator />
        } 
        // 校验登录结果,未登录直接重定向到登录页
        else if (checkLoginResult) {
          return <Component {...props} />
        } else {
          return <Redirect to="/auth/login" />
        }
      }}
    />
  );
};

3. 登出完成后跳转登录页并替换历史栈

调用logoutUserAction时传入当前history实例即可:

export const logoutUserAction = (history) => dispatch => {
  //! Loading
  dispatchLoading(dispatch, LOGOUT_USER_ACTION);

  firebase
    .auth()
    .signOut()
    .then(() => {
      window.localStorage.removeItem('user');
      dispatchSuccess(dispatch, LOGOUT_USER_ACTION, 'Success Logout!!!');
      // 替换当前历史记录为登录页,避免返回键回到受保护页面
      history.replace('/auth/login');
    })
    .catch(() => {
      window.localStorage.removeItem('user');
      dispatchError(dispatch, LOGOUT_USER_ACTION, 'Failed Logout!!!');
      // 登出失败也要跳登录
      history.replace('/auth/login');
    });
};

4. 禁用受保护页面的缓存

在项目public/index.html的head标签中添加以下meta标签,防止浏览器直接读取缓存的历史页面:

<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 12:12:02