React protected route 구현기

JH.P·2024년 7월 17일

구현 배경

  • 사용자에게 보여지게 될 페이지를 로그인 여부에 따라 구분할 필요가 있었다.
  • 로그인한 사용자에게는 기능 사용이 가능한 메인 페이지를 보여주고, 로그인하지 않은 사용자에게는 로그인 페이지만 보여지도록 해야했다.
  • 그리고 이미 로그인을 완료한 사용자는 로그인 페이지 접근을 막아야했다.

로직

  • 라우트 처리를 담당하는 최상위 컴포넌트에서 로그인 전역 상태를 이용하여 분기 처리한다.
  • 로그인을 완료한 사용자에게는 메인 페이지를, 로그인하지 않은 사용자에게는 로그인 페이지만 보이도록 처리한다.

코드

  • Zustand store로부터 로그인 상태를 import한다.
  /** 로그인 전역 상태 */
  const { isLoggedIn } = useAuthStore();
  • 그리고 라우트할 컴포넌트들은 추후 필요한 라우트를 간편하게 추가하기 위해, 그리고 유지보수할 작업이 생길 경우를 고려하여 아래와 같이 배열로 구현하였다. 보호 여부를 구분하기 위해 isPrivate 변수를 선언하여 지정해주었다.
/** 라우트 목록 */
  const routeList = [
    {
      path: "/",
      element: <Home />,
      isPrivate: true,
    },
    {
      path: "/login",
      element: <Login />,
      isPrivate: false,
    },
  ];
  • Protected route 컴포넌트를 아래와 같이 작성하였다.
  • 로그인 상태가 true일 시, 렌더링할 component를 props로 내려받은 것을 확인할 수 있다.
  • 비 로그인 상태일 시, 로그인 페이지로 리다이렉트한다.
import { Navigate, Outlet } from "react-router-dom";
import useStore from "../../store/authStore";

interface ProtectedRouteProps {
  component: React.ReactElement;
}

const ProtectedRoute = ({ component }: ProtectedRouteProps) => {
  const { isLoggedIn } = useStore();

  if (!isLoggedIn) {
    /** 비 로그인 상태일 시, 로그인 페이지 이동 */
    return <Navigate to="/login" replace={true} />;
  }

  /** 컴포넌트 렌더링 */
  return component;
};

export default ProtectedRoute;
  • react-router-dom을 사용하여 라우트 목록을 아래와 같이 작성한다.
  • 보호 여부를 의미하는 isPrivate 변수를 이용하여 분기처리하였다.
  • 만약 isPrivated이 true인 경우, 비 로그인 상태일 시 ProtectedRoute 컴포넌트에 의해 로그인 페이지로 리다이렉트되도록 구현하였다.
  • 그리고 로그인 페이지의 경우, 보호 받아야할 컴포넌트는 아니지만 로그인 상태일 시 접근을 막아야하여 조건을 추가해주었다.
    <BrowserRouter>
      <ThemeProvider theme={theme[themeMode]}>
        <GlobalStyle />
        <CalendarStyle />
        <Layout>
          <UtilsBox themeMode={themeMode} handleFunc={changeTheme} />
          <Routes>
            {routeList.map((route) => {
              const isAuthenticated = isLoggedIn;
              if (route.isPrivate) {
                return (
                  <Route
                    key={route.path}
                    path={route.path}
                    element={<ProtectedRoute component={route.element} />}
                  />
                );
              } else {
                if (route.path === "/login" && isAuthenticated) {
                  return (
                    <Route
                      key={route.path}
                      path={route.path}
                      element={<Navigate to="/" replace />}
                    />
                  );
                }
                return (
                  <Route
                    key={route.path}
                    path={route.path}
                    element={route.element}
                  />
                );
              }
            })}
            <Route path="/*" element={<Navigate to="/" replace />} />
          </Routes>
        </Layout>
      </ThemeProvider>
    </BrowserRouter>
profile
꾸준한 기록

0개의 댓글