简体   繁体   English

React - 未通过身份验证时重定向到登录页面

[英]React - redirect to login page when not authenticated

This is my primary react file:这是我的主要反应文件:

// App.tsx
const App: FC = () => {

  const isLoggedIn: boolean = localStorage.getItem('logged_user') !== null;

  return (
    <BrowserRouter>
        <Routes>
          <Route path="/main" element={isLoggedIn ? <Main/> : <Navigate to='/login'/>}/>
          <Route path="/about" element={isLoggedIn ? <About/> : <Navigate to='/login'/>}/>
          <Route path="/login" element={<Login/>}/>
        </Routes>
    </BrowserRouter>
  );
}

export default App;

After logging in, I store the user in local storage.登录后,我将用户存储在本地存储中。

I want to achieve the behaviour of redirections to the /login page when the user is not authenticated (when it is not stored in localstorage).我想实现在用户未通过身份验证时重定向到 /login 页面的行为(当它未存储在本地存储中时)。

Generally, the above approach works but only sometimes.通常,上述方法有效,但仅在某些时候有效。 Sometimes, when I go to '/main' , I would get redirected to '/login' even though I was logged in. I assume this is caused by React's nature of re-renders.有时,当我 go 到'/main'时,即使我已登录,我也会被重定向到'/login' 。我认为这是由 React 的重新渲染性质引起的。

How can I approach this?我该如何处理?

I'm guessing the redirect to "/login" works the first time, you log in, then try to navigate to "/main" or "/about" and are getting redirected back to "/login" until you do something like a page reload and read any persisted "logged_user" state and then get stuck not being to log out and get redirected back to "/login".我猜重定向到“/login”第一次工作,你登录,然后尝试导航到“/main”或“/about”并被重定向回“/login”,直到你做类似的事情页面重新加载并读取任何持久的“logged_user”state,然后卡住不退出并重定向回“/login”。

You should store the isLoggedIn value in local state, initialized from localStorage, and provide a way within the app to toggle the state.您应该将isLoggedIn值存储在本地 state 中,从 localStorage 初始化,并在应用程序中提供一种方法来切换 state。 Use an useEffect hook to persist local state changes back to localStorage.使用useEffect挂钩将本地 state 更改保留回 localStorage。

Example:例子:

const App: FC = () => {
  const [isLoggedIn, setIsLoggedIn] = useState<boolean>(
    () => localStorage.getItem('logged_user') !== null
  );

  useEffect(() => {
    localStorage.setItem('logged_user', JSON.stringify(isLoggedIn));
  }, [isLoggedIn]);

  
  const logIn = () => setIsLoggedIn(true);

  // pass this callback to components you want to allow logging out
  // it will update the local state and then get persisted
  const logOut = () => setIsLoggedIn(false);

  return (
    <BrowserRouter>
      <Routes>
        <Route path="/main" element={isLoggedIn ? <Main/> : <Navigate to='/login'/>}/>
        <Route path="/about" element={isLoggedIn ? <About/> : <Navigate to='/login'/>}/>
        <Route path="/login" element={<Login onLogIn={logIn} />}/>
      </Routes>
    </BrowserRouter>
  );
}

The way I like to do it, is to create a <PrivateLink /> component, so that it is clear that whatever route is nested requires an authenticated user.我喜欢这样做的方式是创建一个<PrivateLink />组件,因此很明显任何嵌套的路由都需要经过身份验证的用户。

const PrivateRoute = (props: { children: React.ReactNode }): JSX.Element => {
  const { children } = props
  const isLoggedIn: boolean = localStorage.getItem('logged_user') !== null;
  const location = useLocation()

  return isLoggedIn ? (
    <>{children}</>
  ) : (
    <Navigate
      replace={true}
      to="/login"
      state={{ from: `${location.pathname}${location.search}` }}
    />
  )
}

Then in your App.tsx然后在你的 App.tsx

const App: FC = () => (
  <BrowserRouter>
      <Routes>
        <Route path="/main" element={<PrivateRoute> <Main/> </PrivateRoute>}/>
        <Route path="/about" element={<PrivateRoute> <About/> </PrivateRoute>}/>
        <Route path="/login" element={<Login/>}/>
      </Routes>
  </BrowserRouter>
)

As an added extra, the from variable that is passed to the state in the <PrivateRoute /> component, allows you to redirect the user back to whichever page they came from after logging in.作为一个额外的附加功能,在<PrivateRoute />组件中传递给 state 的from变量允许您在登录后将用户重定向回他们来自的任何页面。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM