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

Firebase Auth页面刷新重定向问题:优化AuthRoute逻辑

解决React + Firebase Auth刷新受保护路由时的重定向问题

在React项目中使用Firebase Auth,通过Context Provider共享登录用户信息,并用AuthRoute组件保护特定路由——未登录用户访问时会被重定向到登录页。但存在一个问题:用户登录后访问受保护路由,刷新页面时会被错误重定向到登录页,此时可观察到Firebase Auth调用了https://identitytoolkit.googleapis.com/v1/accounts:lookup接口。

已配置browserLocalPersistence,原本以为是Firebase Auth未优先读取本地存储,而是直接请求认证接口。进一步调研后发现:即使本地存储存在认证信息,Firebase Auth仍会先与服务器异步校验身份,这就是刷新时AuthRoute组件误以为用户未登录的核心原因。

需要修改AuthRoute组件逻辑,满足以下要求:

  • 若本地存储无认证信息,直接重定向至登录页;
  • 若本地存储存在认证信息,等待onAuthStateChanged完成后,根据结果决定渲染受保护内容或重定向至登录页。

原有代码

Firebase初始化代码

const firebaseConfig = {
  apiKey: "...",
  authDomain: "...",
  projectId: "...",
  storageBucket: "...",
  messagingSenderId: "...",
  appId: "...",
};

const firebaseApp = initializeApp(firebaseConfig);
setPersistence(getAuth(), browserLocalPersistence).then(() =>
  console.log("Set persistence: "  + Date.now())
);
export const firebaseAuth = getAuth();

AuthContext Provider核心代码

useEffect(() => {
  const unsubscribe = onAuthStateChanged(firebaseAuth, (currentUser) => {
    setUser(currentUser);
  });
  return unsubscribe;
}, []);

const values = { user, login, signup, logout };
return (
  <AuthContext.Provider value={values}>
    {children}
  </AuthContext.Provider>
);

AuthRoute组件代码

export const AuthRoute: React.FC<Props> = (props) => {
  const { children } = props;
  const location = useLocation();
  const { user } = useUserAuth();

  return user ? (
    <> {children} </>
  ) : (
    <Navigate to="/users/login" state={{ returnUrl: location }} />
  );
};

修改方案

1. 更新AuthContext,添加加载状态

在AuthContext中新增加载状态,用于标识Firebase Auth的服务器校验是否完成:

const [user, setUser] = useState<User | null>(null);
const [isAuthLoading, setIsAuthLoading] = useState(true); // 新增加载状态

useEffect(() => {
  const unsubscribe = onAuthStateChanged(firebaseAuth, (currentUser) => {
    setUser(currentUser);
    setIsAuthLoading(false); // 校验完成后更新状态
  });
  return unsubscribe;
}, []);

const values = { user, isAuthLoading, login, signup, logout };
return (
  <AuthContext.Provider value={values}>
    {children}
  </AuthContext.Provider>
);

2. 修改AuthRoute组件逻辑

在AuthRoute中先检查本地存储的Firebase认证信息,再结合加载状态和用户信息做判断:

import { firebaseConfig } from './path-to-firebase-config'; // 导入firebase配置

export const AuthRoute: React.FC<Props> = (props) => {
  const { children } = props;
  const location = useLocation();
  const { user, isAuthLoading } = useUserAuth();

  // 检查本地存储是否存在Firebase Auth的认证数据
  const authStorageKey = `firebase:authUser:${firebaseConfig.apiKey}:${firebaseConfig.authDomain}`;
  const hasLocalAuthData = Boolean(localStorage.getItem(authStorageKey));

  // 本地无认证数据,直接重定向到登录页
  if (!hasLocalAuthData) {
    return <Navigate to="/users/login" state={{ returnUrl: location }} />;
  }

  // 本地有认证数据,但校验还在进行中,显示加载状态(可替换为项目自定义加载组件)
  if (isAuthLoading) {
    return <div>加载中...</div>;
  }

  // 校验完成,根据用户状态决定渲染内容或重定向
  return user ? (
    <> {children} </>
  ) : (
    <Navigate to="/users/login" state={{ returnUrl: location }} />
  );
};

3. 优化Firebase初始化(可选)

调整初始化顺序,确保持久化配置在Auth实例创建后正确执行:

const firebaseConfig = {
  apiKey: "...",
  authDomain: "...",
  projectId: "...",
  storageBucket: "...",
  messagingSenderId: "...",
  appId: "...",
};

const firebaseApp = initializeApp(firebaseConfig);
const firebaseAuth = getAuth(firebaseApp); // 直接关联app实例

setPersistence(firebaseAuth, browserLocalPersistence)
  .then(() => {
    console.log("Set persistence: " + Date.now());
  })
  .catch((error) => {
    console.error("设置持久化失败:", error);
  });

export { firebaseAuth };

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 18:15:49