페이지 접근 제한

미어캣의 개발일지·2025년 2월 18일
post-thumbnail

사용자를 관리하는 프로젝트에서는 의도하지 않은 페이지 접속을 차단해야 할 경우가 있다.

예를 들어,

  • 비로그인 유저는 프로필, 기록 데이터 등 유저 데이터가 필요한 페이지에 접근할 수 없다.
  • 로그인 유저는 로그인, 회원가입 페이지에 다시 접속할 수 없다.

이를 막기 위해서 아래와 같은 코드를 각 페이지마다 작성할 수도 있다.

  useEffect(() => {
    if (user) {
      navigate("/record");
    } else {
      navigate("/"); 
    }
  }, [user, navigate]);

하지만 매번 각 페이지마다 이런 코드를 작성하면 중복 코드가 많아지기 때문에 더 효율적인 방법이 필요하다.




1. 기본 라우터 설정

보통 App.tsx 파일에 아래와 같이 라우터를 설정한다.

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/login" element={<LoginPage />} />
    <Route path="/signup" element={<SignupPage />} />
    <Route path="/record" element={<RecordsPage />} />
    <Route path="*" element={<ErrorPage />} />
  </Routes>
</BrowserRouter>;

이렇게 설정해주면 각 페이지에서 Link 또는 useNavigate를 사용하여 다른 페이지 이동할 수 있다.


2. PrivateRoute와 PublicRoute로 접근 제어하기

이럴 때, 특정 페이지에 접근을 제한하고 싶다면 privateRoute 컴포넌트를 사용하면된다.

PrivateRoute 예시

const PrivateRoute = ({ children }) => {
  const { user } = useAuth();

  return user ? children : <Navigate to="/login" />;
};

라우터에 적용하는 방법은 다음과 같다.

<Route 
  path="/record" 
  element={
    <PrivateRoute>
      <RecordsPage />
    </PrivateRoute>
  } 
/>

이렇게 설정해두면, 로그인하지 않은 사용자가 RecordsPage에 직접 접근하려 할 경우 자동으로 /login 페이지로 리다이렉트된다. 반대로 로그인한 사용자는 정상적으로 페이지 접근이 가능하다.

PublicRoute 예시

반대로 로그인한 사용자가 login 페이지나 signup 페이지 접근을 제한하기 위해서 publicRoute를 구현했다.

const PublicRoute = ({ children }) => {
  const { user } = useAuth();

  return user ? <Navigate to="/" /> : children;
};

이를 App.tsx에 적용하면 다음과 같은 구조가 된다.

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/login" element={<PublicRoute><LoginPage /></PublicRoute>}/>
    <Route path="/signup" element={<PublicRoute><SignupPage /></PublicRoute>}/>
    <Route path="/record" element={<PrivateRoute><RecordsPage /></PrivateRoute>}/>
    <Route path="/my-records" element={<PrivateRoute><MyRecordsPage /></PrivateRoute>}/>
    <Route path="*" element={<ErrorPage />} />
  </Routes>
</BrowserRouter>;

3. 무한 리다이렉트 문제와 해결 방법

Firebase를 사용하여 데이터를 관리하면서 사용자 인증을 비동기적으로 처리하게 되었다.

이 과정에서 privateRoutePublicRoute를 사용하여 페이지별 접근 제한를 설정했다.

하지만 특정 상황에서 무한 리다이렉트 문제가 발생했다.

문제 발생 시 브라우저에서는 다음과 같은 경고 메시지를 출력했다.

Throttling navigation to prevent the browser from hanging. See https://crbug.com/1038223. Command line switch --disable-ipc-flooding-protection can be used to bypass the protection

이 경고는 지나치게 많은 리다이렉트로 인해 브라우저가 강제로 중지하는 상황을 의미한다.

상황을 확인하니

로그인한 유저가 PrivateRoute로 접근이 제한된 페이지에 진입할 때 문제가 발생했다.

인증 정보가 비동기적으로 로드되면서, 처음에는 user 데이터가 null 값을 가진다. 이후 user 데이터가 정상적으로 로딩되지만, PrivateRoute는 초기 상태에서 user가 없는 것으로 판단해 사용자를 로그인 페이지로 리다이렉트했다.

그 결과, 로그인 페이지에서도 사용자가 이미 인증된 상태로 감지되면서, 다시 원래 페이지로 이동하려는 무한 리다이렉트가 발생하게 되었다.

이 문제는 loading 상태를 추가하여 인증 정보가 완전히 로드되기 전까지 리다이렉트를 방지하는 방식으로 해결하였다.

const PrivateRoute = ({ children }) => {
  const { user, loading } = useAuth();

  if (loading) {
    return null;
  }

  return user ? children : <Navigate to="/login" />;
};
profile
이게 왜 안되지? 이게 왜 되지?

0개의 댓글