[Challenge] 로그인 구현 lv.4

KoEunseo·2023년 3월 19일
0

challenge

목록 보기
6/9

키워드

react
react-router-dom
typescript
recoil
admin & auth
logout

유저 권한에 따른 접근 통제

유저의 role에 따라 접근 권한이 주어지는 경우가 있다. admin 페이지가 대표적이다. 이때는 서버에서도 통제를 해주어야한다. 멘토님이 말씀하시기를 가끔 너무 바쁘고 급해서 백에서 '프론트에서 해주시면 안돼요?' 한다고 한다.. 물론 프론트에서도 통제를 할 수 있다. 그치만 그렇게 했다가 털리면... 누가 책임을 져야할까^^

서버 벨리데이션은 필수적이다
백에서는 본인의 자원에만 접근할 수 있도록 하고 권한에 따라 동작을 제어해야한다.
그제서야 프론트에서 권한에 따라 적절한 자원에 접근하도록 하는 것이다.

Admin 페이지 접근 제어하기

type 추가

타입을 추가해준다. 로그인했고(인증됐고) 어드민인지, 로그인했고 어드민이 아닌지,

//기존의 type
interface RouterElement {
  id: number
  path: string
  label: string
  element: React.ReactNode
  withAuth?: boolean
}
// 추가하는 type
interface UserRouterElement extends RouterBase {
  withAuth?: boolean; // 로그인이 필요한지?
}

interface AdminRouterElement extends RouterBase {
  withAuth: true; // 인증 필수
  isAdminPage?: boolean; // 어드민 페이지인지?
}

type AccessRouterElement = UserAccessibleRouterElement | AdminAccessibleRouterElement;

router list에 admin페이지를 추가한다.

이부분은 내가 공부가 부족해서 이해는 되는데 어려웠다. "isAdminPage" in 이라는 키워드를 사용했는데 이게 자바스크립트 문법인지 타입스크립트 문법인지도 헷깔리고. 이따가 공부해서 아래 추가하겠음! 우선은 admin페이지일 경우 true를 전달한다는 의미다.

나는

isAdminPage={router.isAdminPage ? true : undefined}

이렇게 했는데 멘토님은 아래와 같이 작성하셨다. 아마... 타입스크립트 문법같긴 하다. router에 isAdminPage라는 타입이 있는지 검토하고, 라우터의 isAdminPage가 true인지 확인하는... 타입이 있는지 여부까지 함께 체그해주는 이유는 뭐일까

isAdminPage={"isAdminPage" in router && router.isAdminPage}
export const routers: RemixRouter = createBrowserRouter(
  routerData.map((router) => {
    if (router.withAuth) {
      return {
        path: router.path,
        element: (
          <AuthCheckedFrame
            isAdminPage={"isAdminPage"인지 확인하는 코드}
          >
            {router.element}
          </AuthCheckedFrame>
        ),
      };
    } else {
      return {
        path: router.path,
        element: router.element,
      };
    }
  })
);

sidebar에 admin에게만 페이지가 보이도록 하기

sidebarList.ts

export const SidebarList: SidebarElement[] = routerList.reduce(
  (prev, router) => {
    if (!router.withAuth) return prev;
    return [
      ...prev,
      {
        id: router.id,
        path: router.path,
        label: router.label,
        // isAdminOnly: router.isAdminPage ? true : undefined,
        isAdminOnly: "isAdminPage" in router && router.isAdminPage,
      },
    ];
  },
  [] as SidebarElement[]
);

sidebar.tsx

isAdminOnly가 true일때 + admin유저일때만 admin페이지가 나오도록 필터링한 후 map으로 sidebarList를 뿌려준다.
나는 === 를 사용했는데 includes를 쓰니까 훨씬 간결해지고 의미가 더 잘 드러나는 것 같다. 앞으로 includes를 더 잘 써봐야겠다.

<ul>
  {sidebarContent
    .filter((element) => {
    return element.isAdminOnly
      ? userProfile?.userInfo.roles.includes("admin")
    : !!userProfile;
  })
    .map((element) => {
    return (
      <li
        key={element.path}
        onClick={() => sidebarMenuClickHandler(element.path)}
        >
        {element.label}
      </li>
    );
  })}
</ul>
profile
주니어 플러터 개발자의 고군분투기

0개의 댓글