๐Ÿฌ ๊ธดํ˜ธํก/๊ณ ์Šค๋ฝ ํ‹ฐ์ผ“

[2.0] ๋กœ๊ทธ์ธ ๊ณผ์ •์˜ ๊ณ ๋ฏผ (๋ผ์šฐํŒ…, Axios)

ํ•œ๊ทœ์ง„ 2022. 8. 10. 14:33

๋žœ๋”ฉํŽ˜์ด์ง€์™€ ๋กœ๊ทธ์ธํŽ˜์ด์ง€๋Š” ํ† ํฐ ์—†์ด๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ณ , ๋งˆ์ดํŽ˜์ด์ง€์™€ ํ‹ฐ์ผ“ํŒ… ํŽ˜์ด์ง€๋Š” ์ธ์ฆ์ด ๋˜์–ด ์žˆ๋Š” ์ƒํƒœ์—์„œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ํ‹ฐ์ผ“ QR์ฝ”๋“œ ํŽ˜์ด์ง€๋Š” ์ธ์ฆ์ด ๋˜์–ด ์žˆ์ง€ ์•Š์•„๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค. ํ•œ๋ช…์ด ํ‹ฐ์ผ“์„ ์—ฌ๋Ÿฌ์žฅ์„ ์‚ฌ์„œ '๊ณต์œ ํ•˜๊ธฐ'๋ฅผ ํ†ตํ•ด ์นœ๊ตฌ๋“ค์—๊ฒŒ ์ค„ ์ˆ˜ ์žˆ์–ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—. ๋ผ์šฐํŒ…๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

 

๋ผ์šฐํŒ…

  return (
    <Routes location={location}>
      <Route path="/" element={<Landing />} />
      <Route element={<Layout />}>
        <Route element={<RefuseAuth />}>
          <Route path="/auth/*" element={<AuthRouter />} />
        </Route>
        <Route element={<RequireAuth />}>
          <Route path="/mypage/*" element={<MypageRouter />} />
          <Route path="/ticketing/*" element={<TicketingRouter />} />
        </Route>
        <Route path="/tickets/:ticketId" element={<TicketQR />} />
        <Route path="/404" element={<NotFound />} />
      </Route>
      <Route path="*" element={<Navigate to="/404" />} />
    </Routes>
  );

๋ฌธ์„œ์—์„œ React-Route-dom ๋งŒ์„ ์ด์šฉํ•ด์„œ ์ ‘๊ทผ์„ ์ œํ•œํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•œ ์˜ˆ์‹œ๊ฐ€ ์ž˜ ๋˜์–ด ์žˆ์–ด์„œ ์ฐธ๊ณ ํ–ˆ๋‹ค. 1์ฐจ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ HOC๋กœ ๋งŒ๋“ค์–ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ธ์ž๋ฅผ ๋„˜๊ธฐ๊ณ  ๊ฑธ๋Ÿฌ์„œ ๋ฆฌํ„ดํ•˜๋Š” ๋ฐฉ์‹์— ๋น„ํ•ด ํ›จ์‹  ๊น”๋”ํ•˜๊ณ  ์ง๊ด€์ ์ด์–ด์„œ ์ข‹๋‹ค.

 

 

RequireAuth.tsx

const RequireAuth = () => {
  const { pathname } = useLocation();
  const setRedirectUri = useSetRecoilState(redirectState);

  const accessToken = localStorage.getItem('accessToken');
  const registerToken = localStorage.getItem('registerToken');
  // undefined or token
  useEffect(() => {
    setRedirectUri(pathname);
  }, []);

  if (accessToken) {
    // ์–ด์„ธ์Šค ํ† ํฐ ์žˆ์œผ๋ฉด ํŒจ์Šค
    return <Outlet />;
  } else if (registerToken) {
    // ์–ด์„ธ์Šค ํ† ํฐ ์—†์ด ๋ ˆ์ง€์Šคํ„ฐ ํ† ํฐ๋งŒ ์žˆ์œผ๋ฉด ํšŒ์›๊ฐ€์ž…
    return <Navigate replace to="/auth/init" />;
  } else {
    // ๋‘˜ ๋‹ค ์—†์œผ๋ฉด ๋กœ๊ทธ์ธ..?
    return <Navigate replace to="/auth/login/1" />;
  }
};

export default RequireAuth;

์˜คํ”ˆํ•˜๊ณ  ๊ณต์—ฐ๋‚ ๊นŒ์ง€ ์ผ์ฃผ์ผ์ •๋„ ์งง๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ์„œ๋น„์Šค์ด๋‹ค ๋ณด๋‹ˆ ๋ฆฌํ”„๋ ˆ์‰ฌ ํ† ํฐ์„ ๊ตณ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์–ด์„ธ์Šคํ† ํฐ (์ดํ•˜ AT)๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.

 

RequireAuth๋กœ ๊ฐ์‹ธ์ง„ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•  ๋• AT๊ฐ€ ์žˆ์œผ๋ฉด ํŒจ์Šคํ•˜๊ณ , ์—†์œผ๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ณด๋‚ธ๋‹ค. ๋กœ๊ทธ์ธ์ด ์„ฑ๊ณตํ–ˆ์„ ๋•Œ ํšŒ์›๊ฐ€์ž…๊นŒ์ง€ ์™„๋ฃŒํ•œ ์œ ์ €์ผ ๋•Œ๋Š” AT๋ฅผ ๋ฆฌ์Šคํฐ์Šค๋กœ ์ฃผ์ง€๋งŒ, ํšŒ์›๊ฐ€์ž…์„ ํ•˜์ง€ ์•Š์€ ์ฒซ 1ํšŒ ๋กœ๊ทธ์ธ์ผ๋•Œ๋Š” ๋ ˆ์ง€์Šคํ„ฐ ํ† ํฐ์„ ๋ฐ›๋Š”๋‹ค. ๊ทธ๋Ÿด๋• ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€๋กœ ๋ณด๋‚ด๋ฒ„๋ฆฌ์ž.

 

๋žœ๋”ฉํŽ˜์ด์ง€์—์„œ '์˜ˆ๋งคํ•˜๋Ÿฌ ๊ฐ€๊ธฐ' ๋˜๋Š” '์˜ˆ๋งค ๋‚ด์—ญ ๋ณด๊ธฐ' ๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ ๊ทธ ๋ชฉ์ ์ง€๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ ๋กœ๊ทธ์ธ์ด ๋๋‚œ ํ›„์— ์›๋ž˜ ๋ชฉ์ ์ง€๋กœ ๊ฐ€๋„๋ก ํ•ด์•ผํ–ˆ๋‹ค. redirectUri๋ผ๋Š” ์ƒํƒœ์— ์ €์žฅํ•ด๋‘๊ณ  ๋กœ๊ทธ์ธ ์ดํ›„์— ํ•ด๋‹น ๊ฐ’์„ ๊ฐ€์ ธ์™€ ๋„ค๋น„๊ฒŒ์ดํŠธ ์‹œ์ผœ์ฃผ์—ˆ๋‹ค.

 

RefuseAuth.ts

const RefuseAuth = () => {
  const { openModal, closeModal } = useModal();
  const accessToken = localStorage.getItem('accessToken');
  const registerToken = localStorage.getItem('registerToken');
  // undefined or token
  const location = useLocation();
  if (accessToken) {
    // ์–ด์„ธ์Šค ํ† ํฐ ์žˆ์œผ๋ฉด ๋งˆ์ดํŽ˜์ด์ง€๋กœ ๋˜๋Œ๋ ค๋ฒ„๋ฆผ
    // ์—๋Ÿฌ์ฒ˜๋ฆฌ ๋กœ์ง (์ƒ๋žต)
    return <Navigate replace to="/mypage" />;
  } else if (location.pathname === '/auth/init') {
    // auth/init ์ ‘๊ทผ์ผ๋•Œ, ๋ ˆ์ง€์Šคํ„ฐ ํ† ํฐ ์žˆ์–ด์•ผ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
    if (registerToken) {
      return <Outlet />;
    } else {
      // ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋กœ์ง (์ƒ๋žต)
      return <Navigate replace to="/auth/login/1" />;
    }
  } else {
    // ๋‘˜ ๋‹ค ์—†์œผ๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๊ทธ๋ƒฅ ํŒจ์Šค
    return <Outlet />;
  }
};

export default RefuseAuth;

๋กœ๊ทธ์ธ์„ ํ•˜๊ณ  ํ‹ฐ์ผ“ ์˜ˆ๋งค๋‚˜ ๋งˆ์ดํŽ˜์ด์ง€๋กœ ๋“ค์–ด์™”์„๋•Œ, ๋’ค๋กœ๊ฐ€๊ธฐ๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๋กœ์ง์ด๋‹ค. ํšŒ์›๊ฐ€์ž…ํ•˜๋Š” ๋ถ€๋ถ„์€ ๋ ˆ์ง€์Šคํ„ฐ ํ† ํฐ์„ ๋”ฐ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์—ˆ๋‹ค. 

 

Axios ์„ค์ •

export const axiosPublic = axios.create({
  baseURL: BASE_URL,
  headers: { 'Content-Type': 'application/json' },
});

export const axiosPrivate = axios.create({
  baseURL: BASE_URL,
  headers: { 'Content-Type': 'application/json' },
});

AT๋ฅผ ์‚ฌ์šฉํ•˜๋Š” axiosPrivate๊ณผ, ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” axiosPublic ๋‘ ๊ฐœ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋”ฐ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

 

Recoil

const initialState = {
  isAuthenticated: false,
  registerToken: null,
  phoneNumber: null,
  inProcess: false,
};

const getTokenFromLocalStorage = (): IAuthType => {
  const accessToken = localStorage.getItem('accessToken');
  const registerToken = localStorage.getItem('registerToken');
  if (accessToken) {
    // ์–ด์„ธ์Šคํ† ํฐ์ด ์žˆ์œผ๋ฉด axios ์ธ์Šคํ„ด์Šค์— ์ปค๋จผ ํ—ค๋”๋กœ ์ง‘์–ด๋„ฃ์Œ
    axiosPrivate.defaults.headers.common[
      'Authorization'
    ] = `Bearer ${accessToken}`;

    //์ƒˆ๋กœ๊ณ ์นจํ• ๋•Œ๋งˆ๋‹ค ํ† ํฐ์œผ๋กœ ์œ ์ €์ •๋ณด(์ž…๊ธˆ์ž๋ช…, ์ „ํ™”๋ฒˆํ˜ธ) ๊ฐ€์ ธ์˜ค๋Š” ๊ณผ์ • ํ•„์š”
    return {
      ...initialState,
      isAuthenticated: true,
      registerToken,
    };
  } else return { ...initialState, registerToken };
};

export const authState = atom<IAuthType>({
  key: 'auth',
  default: getTokenFromLocalStorage(),
});

๋ฆฌ์ฝ”์ผ์—์„œ authState๋ฅผ ์ฒ˜์Œ ์ดˆ๊ธฐํ™”ํ• ๋•Œ ์ฟ ํ‚ค์— ์žˆ๋Š” ๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ default ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. AT๊ฐ€ ์žˆ๋‹ค๋ฉด ์ƒํƒœ์— ๋„ฃ๊ณ  axios ์ธ์Šคํ„ด์Šค์˜ ์ปค๋จผ ํ—ค๋”๋กœ ์ง‘์–ด ๋„ฃ๋Š”๋‹ค.

 

์ธ์ฆ์„ ํ•˜๊ณ  ์ด์— ๋”ฐ๋ผ ๋ผ์šฐํŒ…๊ณผ ์—๋Ÿฌ์ฒ˜๋ฆฌํ•˜๋Š” ๋กœ์ง์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌ๋ฅผ ํ•ด๋ณด์•˜๋‹ค. ์ด ์™ธ์— ์—๋Ÿฌ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์•Œ๋ฆผ ๋ชจ๋‹ฌ์„ ๋„์›Œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค. ๋ฆฌ์•กํŠธ ์ฟผ๋ฆฌ๋ฅผ ์ด์šฉํ•ด ์—๋Ÿฌ๋ฅผ ๊ณตํ†ต์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ, ํ”„๋กœ์ ํŠธ ๋‚ด์— ๋‹ค์–‘ํ•œ ๊ณณ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ชจ๋‹ฌ์„ ๋„์šฐ๋Š” ๋ฐฉ๋ฒ•๋„ ์ฐจ์ฐจ ์ •๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค.