TIL_2024_01_25

이종현·2024년 1월 25일
0

Today_I_Learned

목록 보기
127/145
post-thumbnail

Today 요약

  1. 리액트 강의

1. What I Learned?

리액트 강의

권한에 따라 특정 페이지 접근 제한

현재 요구사항 중에 어드민 사용자만 제품 등록 페이지에 접근이 가능해야 한다. 그리고 로그인한 사용자만 장바구니에 접근이 가능해야 한다. 특정 버튼을 누르는 경우에 대해서는 애초에 userInfo 정보와 isAdmin의 값에 따라 버튼을 숨기거나 보여주면 된다.

하지만 주소창에서 직접 접근을 하는 경우에는 어떻게 막아야할까? 강의에서는 라우트를 보호하는 의미로 ProtectedRoute라는 컴포넌트를 이용한다. 원하는 페이지에 해당 컴포넌트를 씌워서 원하는 동작을 하게 만든다.

강의를 보기 전이라면 나는 useEffect로 path가 변경되는 걸 감지해서 해결하려고 했을 것이다. App 컴포넌트에서 useLocation으로 path를 가지고 오고 path가 변경될 때 원하는 로직을 추가한다. path가 /cart이면서 userInfo가 없으면 루트페이지로 리다이렉션 처리를 한다. 그리고 path가 /product/new 이면서 isAdmin이 false면 이 또한 루트페이지로 리다이렉션 한다.

하지만 이런 해결방법은 문제가 있다. App에서 path의 변경을 감지하게 되면, 그 로직은 매번 라우팅 변경이 발생할 때마다 동작하게 된다. 장바구니나 제품 등록 페이지가 아니여도 체크를 하게 된다. 불필요하다.

반면에 강의에서 나온 ProtectedRoute는 특정 페이지에 접근할 때만 동작하게 된다. 자세한 코드를 한 번 쭉 살펴보자.

import { Navigate } from 'react-router-dom'
import { useAuthContext } from '../../context/AuthContext'

interface ProtectedRouteProps {
  children: React.ReactNode
  requireAdmin?: boolean
}

const ProtectedRoute = ({ children, requireAdmin }: ProtectedRouteProps) => {
  const { userInfo, isLoading } = useAuthContext() || {}

  if (isLoading) {
    return <div>로딩 중...</div>
  }

  if (!userInfo || (requireAdmin && !userInfo.isAdmin)) {
    return <Navigate to="/" replace />
  }

  return children
}

export default ProtectedRoute

ProtectedRoute의 전체코드 부터 살펴보자. 일단 유저 정보가 전역에서 관리되며 제공되기 위해서 context를 사용해서 가지고 온다. 그리고 firebase에서 유저 정보를 비동기로 가지고 오기 때문에 유저 정보를 가져오기 전에 ProtectedRoute가 먼저 렌더링 되는 문제가 있었다. 그 부분은 isLoading이라는 boolean 값을 이용해서 해결했다. 그리고 유저 정보가 없거나 제품 등록페이지에서는 어드민 사용자가 아닌 사람만 체크한다. 그리고 해당하면 루트페이지로 리다이렉션 한다. 그리고 사용할 때는 라우트를 구현한 가장 상위에 있는 index.tsx에서 사용한다.

// index.tsx
...

const router = createBrowserRouter([
  {
    path: '/',
    element: <App />,
    children: [
      {
        index: true,
        element: <Home />
      },
      {
        path: 'product/:id',
        element: <Product />
      },
      {
        path: 'product/new',
        element: (
          <ProtectedRoute requireAdmin>
            <NewProduct />
          </ProtectedRoute>
        )
      },
      {
        path: 'login',
        element: <LogIn />
      },
      {
        path: 'register',
        element: <Register />
      },
      {
        path: 'cart',
        element: (
          <ProtectedRoute>
            <Cart />
          </ProtectedRoute>
        )
      }
    ]
  }
])

const rootElement = document.getElementById('root')
if (!rootElement) throw new Error('Root element not found')

const root: ReactDOM.Root = ReactDOM.createRoot(rootElement)
root.render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
)

이렇게 함으로써 사용자가 주소창으로 강제적으로 접근해도 권한과 유저 정보의 유무에 따라 접근을 제한할 수 있다.

profile
데이터리터러시를 중요하게 생각하는 프론트엔드 개발자

0개의 댓글