反应如何设置只有在有人登录时才能访问的私人路线?

react how to setup private routes that can only be accessed when someone is signed in?

我正在尝试制作一个带有 react-google-login SSO 身份验证的网站,我想制作一条私​​人路线,如果没有用户登录,则没有人可以访问这些路线甚至可以看到侧边栏组件。即使他们尝试通过 url.

访问路由,也将始终被重定向到登录页面

这是我的 app.js

  function App() {
  const [value,setValue] = useState()
  const [loggedIn, setLoggedIn] = useState()

  
  return (
    <>
    <Column style={{ width: "100%" }}>
      <Row horizontal="start" style={{ backgroundColor: "#0C5494" }}>
        <a href="/">
        <img alt="logo" className="photo" src={logo}/>
        </a> 
        </Row>
      <BrowserRouter>
      <Row >
      <Column
            flexGrow={1}
          >
        <PrivateRoute>
        <Route path="/" element={<Sidebar/>}></Route>
        </PrivateRoute>
        </Column>
        <Column
            vertical="start"
            flexGrow={100}
           // style={{ backgroundColor: "pink"}}
          >
          <div className="mainContent">
          <AuthContext.Provider value={{loggedIn,setLoggedIn}}>
          <TableCountContext.Provider value={{value,setValue}}>
          <PrivateRoute>
          <Route exact path="/" element={<RealHome/>}></Route>
          <Route exact path="/search" element={<Home/>}></Route>
          
          <Route path="/login" element={<Login/>}></Route>
     
          <Route path="/FAQ" element={<Faq/>}></Route>
         
          <Route path="/Search-sec" element={<SearchSec/>}></Route>
          </PrivateRoute>
          </TableCountContext.Provider>
          </AuthContext.Provider>
          </div>
          
          </Column>
        </Row>
        
      </BrowserRouter>
      </Column>
    </>
  )
}

export default App

这是我的 google 登录按钮:

 export default function GoogleLoginButton() {
    const clientId = "myGoogleID.apps.googleusercontent.com"
    const [showLoginButton, setShowLoginButton] = useState(true)
    const [showLogoutButton, setShowLogoutButton] = useState(false)
    const {loggedIn,setLoggedIn} = useContext(AuthContext)
    let navigate = useNavigate()
    const onLoginSuccess = (res) =>{
        console.log("Login Success:", res.profileObj);
        setShowLoginButton(false)
        setShowLogoutButton(true)
        setLoggedIn(localStorage.getItem('isLoggedIn'))
        localStorage.setItem('isLoggedIn', true);
        console.log(localStorage.getItem('isLoggedIn'))
        console.log(loggedIn)
        navigate(`/`)
    }
    const onLoginFailure = (res)=>{
        console.log("Login Failed:", res)
    }

    const onSignoutSuccess = () =>{
        alert("You have been signed out successfully.")
        setShowLoginButton(true)
        setShowLogoutButton(false)
        setLoggedIn(localStorage.getItem('isLoggedIn'))
        localStorage.setItem('isLoggedIn', false);
        console.log(localStorage.getItem('isLoggedIn'))
        console.log(loggedIn)
    }
  
    
    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>
    )
}

这是我的 PrivateRoute.js

import React, {useContext} from "react"
import {Navigate,Route,Routes} from "react-router-dom"
import { AuthContext } from "./Contexts"

export default function PrivateRoute({ component: Component, ...rest }) {
  const { loggedIn } = useContext(AuthContext)

  return (
    <Routes>
    <Route
      {...rest}
      render={props => {
        return loggedIn ? <Component {...props} /> : <Navigate to="/login" />
      }}
    ></Route>
    </Routes>
  )
}

这是我的 Contexts.js

import { createContext } from "react";

export const TableCountContext = createContext(null)
export const AuthContext = createContext(false)

我使用 redux 登录,在这种情况下你可以编写 react-router-component,来检查用户是否登录

const ProtectedRoute = ({ component: Component, ...props }) => {
  const { isLoggedIn } = props;
  return (
    <Route render={(props) => (
      !isLoggedIn ? <Component {...props} /> : <Redirect to={{/loginPage}}>/>
    )} {...props} />
  );
};

const mapStateToProps = (state) => ({
  isLoggedIn: state.user.isLoggedIn
})

export default connect(mapStateToProps)(ProtectedRoute)

以下答案适用于 react-router 版本 6。

根据您是否登录有条件地添加路由,并根据您的需要添加一个或多个重定向:

<Routes>
    <Route path={"/"} element={ <StartPage/> }/>
    <Route path={"/example"} element={ <ExamplePage/> }/>
    <Route path={"/otherpage"} element={ <AnotherPage/> }/>
    {
        isLoggedIn ?
            [ 
                // add as many as you'd like here
                <Route path={"/loggedinpage"} element={ <LoggedInPage/> }/>
            ]
            :
            null
    }
    // take care of redirects for all paths that doesn't match the defined
    <Route path={"*"} element={ <Navigate replace to={ "/" }/> }/>
</Routes>

当没有为登录用户定义路径时,这些路径将与所有路径匹配,用户将被重定向到 /,而当存在这些路径时(例如,用户已登录in), 会匹配到有问题的路径并显示相应的内容

提醒一句:请注意,如果您计划从后端提供自定义内容,则需要有一些安全机制来了解用户是否真的登录,例如不要只相信前端说“我以这个和这个用户的身份登录”。你可能已经知道了,但只是说清楚。