React Router - (4. 공개 라우트와 비공개 라우트)

eeensu·2023년 12월 19일
0

React 실무

목록 보기
18/22
post-thumbnail

배경

보통의 웹 사이트에서는 로그인을 진행해야 웹 사이트의 주요 서비스를 이용할 수 있다. 보안과 식별을 위해, 해당 유저의 개인정보를 바탕으로한 서비스가 필요할 때, 유저 인증 구현이 필요하다. 보통 홈 페이지, 로그인 페이지, 회원 가입 페이지 처럼 누구든 접속이 가능한 경로를 공개 라우트(public route)라 한다. 반면 인증된 유저만 접속할 수 있는 경로를 비공개 라우트(private route)라 한다.

과거에는 웹 페이지의 대부분이 공개적으로 접근 가능한 컨텐츠였다. 웹 페이지는 주로 정보를 제공하는 목적으로 사용되었고, 대다수의 웹 사이트가 사용자 인증 없이 접근 가능한 컨텐츠를 제공했다. 이러한 컨텐츠는 홈페이지, 랜딩 페이지, 뉴스 등이 있다.

하지만 인터넷이 발전하면서 웹 애플리케이션은 점점 복잡해지고 다양한 종류의 데이터와 기능을 다루게 되었다. 사용자의 개인 정보, 결제 정보, 민감한 데이터 등을 다루는 경우 이러한 데이터를 보호하고자 특정한 사용자만 접근할 수 있는 비공개 페이지가 필요해졌다. 이를 위해 사용자 인증 및 권한 부여 시스템이 개발되었고, 비공개 라우터가 도입되었다. 이러한 공개 비공개 로직을 React 어플리케이션에서는 어떻게 다루는지 알아보자.




공개 인증 컴포넌트

유저가 인증이 필요한 페이지에 진입하기 전에, 해당 유저가 요구되는 인증을 체크했는지의 여부를 확인하는 공개 인증 컴포넌트를 제작한다.

import type { FC } from 'react';
import { Navigate, Outlet, useLocation } from 'react-router-dom';
import { useUserStore } from '../../zustand';

type Props = {
    allowedRoles: UserLicense[];					
  // 어떤 유저들이 접근할 수 있는지에 대한 정보가 담긴 배열 타입 ex) 'USER', 'ADMIN', ...
}

const RequireAuth: FC<Props> = ({ allowedRoles }) => {
  
    // 어떤 페이지로부터 왔는지에 대한 정보를 전달하기 위해 location을 가져온다.
    const location = useLocation();								

    // 해당 로직은 zustand를 활용한 전역 스토어.
    // 현재 접속한 유저의 로그인 여부와 유저 라이선스에 대한 정보가 담겨있다.
    const { isLogin, user_license } = useUserStore();				

    return (
      	// 해당 페이지에 허락된 Role과 유저가 가지고 있는 Role 중에 일치하는 게 있으면 접속 허용
        allowedRoles.find(role => role === user_license) ? 			
            <Outlet />
            : isLogin 	 // 불일치 하면서 로그인 상태이면 접속 불가 페이지 리턴, 아니라면 로그인 페이지로 이동
                ? <Navigate to='/unauthorized' state={{ from: location }} replace />
                : <Navigate to='/loginPage' state={{ from: location }} replace />
    );
}

export default RequireAuth;

return 문에서, 접속하려는 인증 요구 페이지에 부여된 허락된 역할 allowedRoles에서 find 메서드를 이용해 허용된 role과 유저의 license가 일치하는 부분이 있는지 찾는다. 만약 일치되는 역할이 있으면 진입 가능한 (= 인증에 성공한) 상태이며, <Route /> 컴포넌트 내에서 children 컴포넌트를 리턴하는 <Outlet />을 부른다.

또한 로그인한 상태이면서 허용되는 role을 찾지 못했으면 (=인증에 실패 하면) 접근 권한이 없다는 페이지임을 알리는 페이지로 리턴시킨다.

만약 로그인한 상태가 아니라면, 로그인 페이지로 이동하여 사용자에게 로그인 (인증)을 유도한다.



이제 이 모두를 아우르는 <App /> 컴포넌트를 살펴보자.

const App = () => {
    
    return (
        <BrowserRouter>
            <Routes>
                  .
                  .
                  .
                <Route path='/unauthorized' element={<Unauthorized />} />       
                 
                <Route element={<RequireAuth allowedRoles={[ROLES.USER, ROLES.ADMIN]} />}>              .
                  .
                  .
                </Route>          

                <Route element={<RequireAuth allowedRoles={[ROLES.ADMIN]} />}>     
                    .
                    .
                    .
                </Route>                                                                                

                <Route element={<RootLayout />}>
                    <Route path='/loginPage' element={<LoginPage />} />  
                </Route>                     
                   
                <Route element={<RequireAuth allowedRoles={[ROLES.USER, ROLES.ADMIN]} />}>
                    <Route element={<RootLayout type='other' isLogo={false} />}>
                        <Route path='/my-page' element={<MyPage />} />
                    </Route>
                </Route>
                <Route path='*' element={<NotFound />} />             
            </Routes>
        </BrowserRouter>
    );
}

만약, 인증이 필요한 컴포넌트혹은 페이지가 있다면 (마이 페이지, 관리자 페이지 등등) 해당 컴포넌트에 진입하기 전에 <Route /> 컴포넌트의 element<RequiredAuth /> 를 감싸준다. 그리고 진입을 허락할 Role을 부여해준다. 이렇게 하면 마이 페이지, 관리자 페이지 등에 접근하기 전에 인증을 한번 거쳐주고, 해당 유저의 라이선스에 따라 진입을 성공시켜줄지, 아니면 제어시켜줄 지 정할 수 있게 된다.



이러한 방식으로 React Router를 사용하여 공개 및 비공개 라우트를 설정할 수 있다. 해당 위의 예제는 필자가 만든 포트폴리오의 일부이다. 때문에 개발하고 있는 프로젝트의 규모나 동작 방식에 코드를 알맞게 수정해야 할 것이다.

profile
안녕하세요! 26살 프론트엔드 개발자입니다! (2024/03 ~)

0개의 댓글