드림코딩 쇼핑몰 프로젝트 이슈 #1

dodog·2023년 2월 3일
1

문제 해결 기록

목록 보기
1/3

발생한 이슈

장바구니 페이지는 로그인 된 상태에서만 접근 권한이 있고
새 상품추가 페이지도 로그인 된 상태의 관리자만 접근 권한이 있도록 구현해야했다.
강의에서는 이런 권한없는 접근을 차단하기 위해서 이렇게 알려주었다.

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

const ProtectedRoute = ({ children, requireAdmin }) => {
  const { user } = useAuthContext();
  if (!user || (requireAdmin && !user.isAdmin)) {
    return <Navigate to='/' replace />;
  }
  return children;
};

export default ProtectedRoute;

잘못된 접근이 차단되긴 한다. 하지만 심각한 문제가 있었다.

문제점

주소창을 통한 접근조차 완전히 차단되어 버리게 되었다.
로그인을 했어도, 관리자 권한이 있어도 클릭을 통해 들어오는게 아니면 전부 차단된다.
장바구니에서 새로고침을 할때마다 계속 홈으로 보내주니까 너무 답답했다.

원인

useAuthContext() hook을 통해서 user를 받아오는 부분이 문제였다.
useAuthContext 내부에서 비동기적으로 user값이 생성되기 때문에
새로고침이나 주소창으로 접근하면
user를 받아오기도 전에 로그인 여부 및 관리자 확인 로직이 먼저 실행되어
user는 undefined이므로 무조건 차단되어버린다.

해결방법

원래 이 user값을 받아올 때까지 기다리도록 구현해보려고 했는데
useEffect, async await 등 온갖 방법을 다 떠올렸지만 쉽지 않았다.
그래서 그냥 로그인이 되면 localStorage에 userId와 isAdmin정보만 담아주기로 했다.

onUserStateChange((user) => {
  setUser(user);
  localStorage.setItem('user',
    JSON.stringify({ uid: user.uid, isAdmin: user.isAdmin })
  );
});

useEffect 내부에서 user값을 할당해준 뒤에
보안을 위해 localStorage에 uid, isAdmin만 빼서 객체로 묶어 키값으로 넣어주었다.

근데 이때 이 코드에는 더 심각한 문제가 있음을 깨닫게 되었다.
localStorage에 isAdmin값을 넣어두면 일반유저가 로컬스토리지에서 isAdmin = false를
true로만 바꾸면 관리자 권한이 되어버린다는 문제가 있었다.

그래서 또 급히 수정해서
어차피 userId만 있어도 db에서 admin인지 체크가 가능하기 때문에

localStorage.setItem('user', user.uid);

이렇게 userId만 로컬 스토리지에 넣어준 다음

import { isAdminUser } from '../api/firebase';

const ProtectedRoute = ({ children, requireAdmin }) => {
  const uid = localStorage.getItem('user');
  if (!uid || (requireAdmin && !isAdminUser(uid))) {
    return <Navigate to='/' replace />;
  }
  return children;
};

이렇게 boolean값을 반환하는 isAdminUser(uid)를 통해 체크하기로 했다.

로그아웃할때는

localStorage.setItem('user', null);

이렇게 값을 비워주는 처리도 했었는데
계속 로그아웃 처리가 제대로 되지 않아서 헤매다가
또 어처구니 없는 실수를 했을을 깨닫게 되었다.

localStorage.setItem('user', '');

로컬스토리지에는 string값만 저장이 가능해서 이렇게 수정해주어야 했다.
아니면 'null' 이렇게 값이 저장된다.

결과

드디어 새로고침이나 주소창으로 접근을 해도 올바르게 동작하게 되었다.
useAuthContext만 활용해서 전부 해결을 하고 싶었는데
localStorage까지 사용하게 되어 약간 깔끔하지 못한 것 같은 느낌도 있다.

이슈를 해결하는 과정에서 또 다른 이슈도 많이 발생했었는데
이렇게 실수하면서 문제를 겪어보니
다음번에는 같은 문제를 겪지 않을 수 있을 것 같다.

근데 왜 강의에서는 이런 문제를 차후에라도 알려주고 수정해주지 않았는지 모르겠다..

profile
심리학, 사회문제해결에 관심이 많은 프론트엔드 개발자

0개의 댓글