React集成react-google-login SSO时如何配置仅登录可访问的私有路由
React Google SSO 私有路由实现修复方案
现有代码核心问题点:
- 使用的react-router-dom v6版本不兼容旧版v5的路由
render写法,原有PrivateRoute组件无法生效 - AuthContext的包裹范围未覆盖侧边栏区域,侧边栏无法获取登录状态
- 登录/登出逻辑中状态更新顺序错误,先读取localStorage再赋值,导致状态更新滞后
- 登录路由被包裹在私有路由内,未登录用户无法正常访问登录页
- 登录状态未做持久化初始化,页面刷新后登录状态丢失
对应文件修改代码
1. App.js 调整
import {useState} from 'react' import {BrowserRouter, Routes, Route} from 'react-router-dom' // 其他组件、样式导入省略 function App() { const [value,setValue] = useState() // 初始化从localStorage读取登录状态,转布尔值避免字符串判断错误 const [loggedIn, setLoggedIn] = useState(() => { return localStorage.getItem('isLoggedIn') === 'true' }) return ( <> <Column style={{ width: "100%" }}> <Row horizontal="start" style={{ backgroundColor: "#0C5494" }}> <a href="/"> <img alt="logo" className="photo" src={logo}/> </a> </Row> {/* 把Context提到最外层,覆盖所有路由相关组件 */} <AuthContext.Provider value={{loggedIn,setLoggedIn}}> <TableCountContext.Provider value={{value,setValue}}> <BrowserRouter> <Row > <Column flexGrow={1}> {/* 私有路由包裹侧边栏,未登录不显示 */} <PrivateRoute> <Sidebar/> </PrivateRoute> </Column> <Column vertical="start" flexGrow={100} > <div className="mainContent"> <Routes> {/* 公开路由:不需要登录即可访问 */} <Route path="/login" element={<Login/>}></Route> {/* 私有路由:需要登录才能访问 */} <Route path="/" element={ <PrivateRoute> <RealHome/> </PrivateRoute> }></Route> <Route path="/search" element={ <PrivateRoute> <Home/> </PrivateRoute> }></Route> <Route path="/FAQ" element={ <PrivateRoute> <Faq/> </PrivateRoute> }></Route> <Route path="/Search-sec" element={ <PrivateRoute> <SearchSec/> </PrivateRoute> }></Route> </Routes> </div> </Column> </Row> </BrowserRouter> </TableCountContext.Provider> </AuthContext.Provider> </Column> </> ) } export default App
2. GoogleLoginButton.js 调整登录/登出逻辑
export default function GoogleLoginButton() { const clientId = "myGoogleID.apps.googleusercontent.com" // 初始化按钮显示状态和本地存储同步 const [showLoginButton, setShowLoginButton] = useState(() => { return localStorage.getItem('isLoggedIn') !== 'true' }) const [showLogoutButton, setShowLogoutButton] = useState(() => { return localStorage.getItem('isLoggedIn') === 'true' }) const {loggedIn,setLoggedIn} = useContext(AuthContext) let navigate = useNavigate() const onLoginSuccess = (res) =>{ console.log("Login Success:", res.profileObj); // 先更新本地存储,再更新全局状态 localStorage.setItem('isLoggedIn', true); setLoggedIn(true) setShowLoginButton(false) setShowLogoutButton(true) navigate(`/`) } const onLoginFailure = (res)=>{ console.log("Login Failed:", res) } const onSignoutSuccess = () =>{ alert("You have been signed out successfully.") // 先更新本地存储,再更新全局状态 localStorage.setItem('isLoggedIn', false); setLoggedIn(false) setShowLoginButton(true) setShowLogoutButton(false) navigate('/login') } return ( <div> {showLoginButton ? <GoogleLogin clientId={clientId} buttonText="Login" onSuccess={onLoginSuccess} onFailure={onLoginFailure} cookiePolicy={"single_host_origin"} isSignedIn={true} /> : null } {showLogoutButton ? <GoogleLogout clientId={clientId} buttonText="Sign Out" onLogoutSuccess={onSignoutSuccess} /> : null} </div> ) }
3. PrivateRoute.js 适配react-router-dom v6重写
import React, {useContext} from "react" import {Navigate} from "react-router-dom" import { AuthContext } from "./Contexts" export default function PrivateRoute({ children }) { const { loggedIn } = useContext(AuthContext) // 已登录返回子组件,未登录重定向到登录页,replace参数避免登录后回退到登录页 return loggedIn ? children : <Navigate to="/login" replace /> }
4. Contexts.js 无需修改,保持原有配置即可
import { createContext } from "react"; export const TableCountContext = createContext(null) export const AuthContext = createContext(false)
修改后即可实现需求:未登录用户访问任意受保护路由都会被重定向到登录页,侧边栏仅在登录后展示。
内容的提问来源于stack exchange,提问作者mirkovski
相关产品推荐
相关产品推荐

