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

React JS & Firebase V9:已登录用户刷新页面被重定向至登录页求助

问题核心原因
  1. 用户认证状态初始化模糊:UserAuthContext 初始将 user 设为空对象,无法区分「认证未完成」和「无登录用户」两种状态,页面刷新后初始阶段会误判为无用户。
  2. 权限判断时机失效:App.js 中判断管理员的 useEffect 依赖为空数组,仅执行一次,此时 user 和 adminUsers 可能还未加载完成,导致 isAdmin 始终为 false。
  3. 路由保护逻辑不符合需求:ProtectedRoute 直接将所有非管理员用户重定向,违背了「员工可访问特定页面」的设计要求。
分步修复方案

1. 修正 UserAuthContext 的用户状态初始化

把初始 user 设置为 null,明确区分认证未完成和无用户的状态:

const userAuthContext = createContext()

export function UserAuthContextProvider({ children }) {
  // 初始设为null,区分未初始化和无登录用户
  const [user, setUser] = useState(null)

  function logIn(email, password) {
    return signInWithEmailAndPassword(auth, email, password)
  }

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user)
    })
    return () => unsubscribe()
  }, [])

  return (
    <userAuthContext.Provider value={{ user, signUp, logIn, logOut }}>
      {children}
    </userAuthContext.Provider>
  )
}

export function useUserAuth() {
  return useContext(userAuthContext)
}

2. 调整 App.js 的权限判断逻辑

更新 useEffect 依赖,确保 user 或管理员列表更新时重新判断权限,同时新增员工状态标识:

const { user } = useUserAuth()
 
const [adminUsers, setAdminUsers] = useState([])
const [isAdmin, setIsAdmin] = useState(false)
const [isEmployee, setIsEmployee] = useState(false)

// 加载管理员列表
useEffect(() => {
  getAdmins()
}, [])

const getAdmins = async () => {
  const data = await PrivateUserDataService.getAdminUsers()
  setAdminUsers(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })))
}

// 当user或adminUsers变化时,重新判定权限
useEffect(() => {
  if (!user) return
  
  const adminEmails = adminUsers.map(admin => admin.email)
  const isCurrentAdmin = adminEmails.includes(user.email)
  
  setIsAdmin(isCurrentAdmin)
  // 员工定义为已登录但非管理员的用户,可根据实际需求调整
  setIsEmployee(!isCurrentAdmin)
}, [user, adminUsers])

return (
  <div className="App">
    <BrowserRouter>
      <Routes>
        <Route path="/">
          <Route index element={<Login />} />
          {/* 仅管理员可访问的首页 */}
          <Route path="home" element={
            <ProtectedRoute requireAdmin={true} isAdmin={isAdmin} isEmployee={isEmployee}>
              <Home />
            </ProtectedRoute>
          } />
          {/* 员工和管理员都可访问的页面 */}
          <Route path="rapport_passage" element={
            <ProtectedRoute requireAdmin={false} isAdmin={isAdmin} isEmployee={isEmployee}>
              <RapportPassage />
            </ProtectedRoute>
          } />
        </Route>
      </Routes>
    </BrowserRouter>
  </div>
);

3. 重构 ProtectedRoute 的路由保护逻辑

新增 requireAdmin 参数,根据页面需求控制权限,同时处理认证加载中的过渡状态:

const ProtectedRoute = ({ children, requireAdmin, isAdmin, isEmployee }) => {
  const { user } = useUserAuth()

  // 认证未完成时,显示加载状态(避免误重定向)
  if (user === null) {
    return <div>加载中...</div> // 可替换为自定义加载组件
  }

  // 未登录用户直接重定向到登录页
  if (!user) {
    return <Navigate to='/' />
  }

  // 需要管理员权限但当前不是管理员,重定向到登录页
  if (requireAdmin && !isAdmin) {
    return <Navigate to='/' />
  }

  // 不需要管理员权限,员工或管理员均可访问
  if (!requireAdmin && (isAdmin || isEmployee)) {
    return children
  }

  // 其他异常情况重定向
  return <Navigate to='/' />
}

export default ProtectedRoute
额外优化建议
  • 可将管理员判断逻辑整合到 UserAuthContext 中,让权限逻辑更集中,避免跨组件重复处理。
  • 加载状态可替换为更友好的UI组件,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 05:10:22