ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๐Ÿ”

๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋‹ค ๋ณด๋ฉด ๋ฐ˜๋“œ์‹œ ๋งˆ์ฃผ์น˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š”๋ฐ
๋ฐ”๋กœ ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ฅธ ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋‹ค.

๋‚˜๋„ ์ด๋ฒˆ์— ๋กœ๊ทธ์ธ ํ”Œ๋กœ์šฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ๋กœ๊ทธ์ธ ์ธ์ฆ์ด ์„ฑ๊ณต ์ƒํƒœ(200 ์ฝ”๋“œ)์ธ๋ฐ๋„ ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™์ด ์•ˆ ๋˜๋Š” ์ƒํ™ฉ์„ ๊ฒช์—ˆ๊ณ  ๊ทธ ๊ณผ์ •์—์„œ ๋กœ๊ทธ์ธ/๋น„๋กœ๊ทธ์ธ ๋ผ์šฐํŒ… ๊ตฌ์กฐ๋ฅผ ํ•œ ๋ฒˆ ์ œ๋Œ€๋กœ ์ •๋ฆฌํ•˜๊ฒŒ ๋๋‹ค.


 

๋ฌธ์ œ ์ƒํ™ฉ

์ฒ˜์Œ์—” ์ด๋Ÿฐ ๊ตฌ์กฐ์˜€๋‹ค.

/**
  * fileName : useCheckAuth
  * description : ๋กœ๊ทธ์ธ ์ƒํƒœ ํ™•์ธ ํ›„ ํ•„์š” ์‹œ ํ† ํฐ ๊ฐฑ์‹  ๋ฐ ํŽ˜์ด์ง€ ์ด๋™์„ ๊ฒฐ์ •ํ•˜๋Š” ์ปค์Šคํ…€ ํ›…
  */
export const useCheckAuth = () => {
  const { data, isLoading, isError, refetch } = useAuthQuery(); // ๋กœ๊ทธ์ธ ์ƒํƒœ ํ™•์ธ
  
  ...
  
  if (data) {
    const code = data.code; // ์‘๋‹ต ์ฝ”๋“œ
  
    if (code === 200) return { isLoading: false, navigateTo: "/home", showChildren: true };
  
    ...
  } 
  
  return { isLoading: false, navigateTo: "/login", showChildren: false }; 
  
};
/**
  * fileName : ProtectRoute
  * description : ์ธ์ฆ์ด ํ•„์š”ํ•œ ๋ผ์šฐํŠธ๋ฅผ ๋ณดํ˜ธํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ. ๋กœ๊ทธ์ธ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋งŒ ํŽ˜์ด์ง€ ์ ‘๊ทผ ํ—ˆ์šฉ
  */
export default function ProtectedRoute({ children }: { children: React.ReactNode; }) { 
  const { isLoading, navigateTo, showChildren } = useCheckAuth();
    
  ...
  
  if (navigateTo) return <Navigate to={navigateTo} replace />;
  
  if (showChildren) return children;
}

 

๊ฒ‰๋ณด๊ธฐ์—๋Š” ๋ฌธ์ œ ์—†์–ด ๋ณด์˜€๋‹ค.
ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ๊ตฌ์กฐ์ ์œผ๋กœ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•œ๋‹ค.

 

๋ญ๊ฐ€ ๋ฌธ์ œ์˜€๋‚˜?

ํ•ต์‹ฌ์€ ๐Ÿ‘‰ navigateTo์™€ showChildren์„ ๋™์‹œ์— ์“ฐ๊ณ  ์žˆ์—ˆ๋‹ค.

ProtectedRoute์—์„œ /home์œผ๋กœ ๋ณด๋‚ด๋Š” ๋กœ์ง ์ž์ฒด๊ฐ€ ๊ตฌ์กฐ์ ์œผ๋กœ ์–ด์ƒ‰ํ•œ ์ƒํƒœ์ธ๊ฑฐ๋‹ค.

์ฆ‰, ์ธ์ฆ ์„ฑ๊ณต ์‹œ ์ด๋™๋„ ํ•˜๋ ค๊ณ  ํ•˜๊ณ  ๋ Œ๋”๋ง๋„ ํ•˜๋ ค๊ณ  ํ•œ๋‹ค.

 

์ปค์Šคํ…€ ํ›…์—์„œ code === 200์ด๋ฉด:

  • navigateTo: "/home"
  • showChildren: true

๋‘˜ ๋‹ค true์ธ ์ƒํƒœ์ด๋‹ค.

 

์ด ์ƒํƒœ์—์„œ ์‹คํ–‰ ์ˆœ์„œ๋Š”:

  1. navigateTo ๋จผ์ € ์‹คํ–‰๋จ
  2. showChildren์€ ์•„์˜ˆ ๋ Œ๋”๋ง ์•ˆ ๋จ

๊ฒŒ๋‹ค๊ฐ€ /home์—์„œ๋„ ProtectedRoute๋ฅผ ์“ฐ๊ณ  ์žˆ์œผ๋ฉด ์ž๊ธฐ ์ž์‹ ์œผ๋กœ ๊ณ„์† redirect๋ฅผ ์‹œ๋„ํ•œ๋‹ค.

๊ฒฐ๊ณผ๋Š” ์ด๋™์ด ์•ˆ ๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ฑฐ๋‚˜ ๋ฌดํ•œ ๋ฃจํ”„๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

๐Ÿ’ก ํ•ด๊ฒฐ ๋ฐฉํ–ฅ

๋ผ์šฐํŠธ ๊ฐ€๋“œ๋Š” ์ด๋™์‹œํ‚ค๋Š” ์—ญํ• ์ด ์•„๋‹ˆ๋‹ค

 

์‚ฌ์‹ค ์ด ๋กœ์ง์€ ์„ค๊ณ„๊ฐ€ ์ž˜๋ชป๋œ๊ฑฐ๋‹ค.

์ธ์ฆ์— ์„ฑ๊ณตํ–ˆ๋Š”๋ฐ ์™œ /home์œผ๋กœ ์ด๋™์‹œํ‚ค๋‚˜?

ProtectedRoute๋Š” ์›๋ž˜ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋‹ด๋‹น์ด ์•„๋‹ˆ๋ผ ๊ทธ ๊ฐ’๋งŒ ๋ณด๊ณ  ์ ‘๊ทผ ํ—ˆ์šฉ์ด๋‚˜ ์ฐจ๋‹จ๋งŒ ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

์—ญํ•  ๋ถ„๋ฆฌ

์ธ์ฆ ์ƒํƒœ ํŒ๋‹จ useCheckAuth
์ ‘๊ทผ ํ—ˆ์šฉ/์ฐจ๋‹จ ProtectedRoute
๋กœ๊ทธ์ธ ์œ ์ € ์ ‘๊ทผ ์ฐจ๋‹จ PublicRoute
ํŽ˜์ด์ง€ ์ด๋™ ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ

 

ProtectedRoute๋Š” UI๋ฅผ ๋‹ด๋‹นํ•˜๊ณ 
useCheckAuth๋Š” ์ธ์ฆ ์ƒํƒœ๋ฅผ ํŒ๋‹จํ•œ๋‹ค.

 

 

 

์˜ฌ๋ฐ”๋ฅธ ๊ตฌ์กฐ

๋ผ์šฐํŒ…์€ 2๊ฐœ๋กœ ๋‚˜๋ˆˆ๋‹ค.

 

์ธ์ฆ ํ•„์š” ๋ผ์šฐํŠธ (Private)

  • ๋กœ๊ทธ์ธํ•ด์•ผ ์ ‘๊ทผ ๊ฐ€๋Šฅ
  • ์˜ˆ: /home, /mypage

๋น„์ธ์ฆ ์ „์šฉ ๋ผ์šฐํŠธ (Public)

  • ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฉด ์ ‘๊ทผํ•˜๋ฉด ์•ˆ ๋จ
  • ์˜ˆ: /login, /signup

 

1. ์ธ์ฆ ์ƒํƒœ ์ปค์Šคํ…€ ํ›…

export const useCheckAuth = () => {
  const { data, isLoading, isError } = useAuthQuery();

  if (isLoading) {
    return { isLoading: true, isAuthenticated: false };
  }

  if (isError) {
    return { isLoading: false, isAuthenticated: false };
  }

  // ์ด๋™์‹œํ‚ค์ง€ ๋ง๊ณ  ๊ทธ๋ƒฅ ํ†ต๊ณผ
  if (data?.code === 200) {
    return { isLoading: false, isAuthenticated: true };
  }

  return { isLoading: false, isAuthenticated: false };
};

ํ•ต์‹ฌ์€ isAuthenticated ํ•˜๋‚˜๋กœ ๋‹จ์ˆœํ™”ํ•˜์—ฌ ๋‹จ์ผ ์ฑ…์ž„ + ๋‹จ์ˆœ ๋กœ์ง์œผ๋กœ ๋ฒ„๊ทธ๋ฅผ ๊ฐ์†Œํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

2. ProtectedRoute (๋กœ๊ทธ์ธ ํ•„์š” ํŽ˜์ด์ง€ ๋ณดํ˜ธ)

export default function ProtectedRoute({ children }) {
  const { isLoading, isAuthenticated } = useCheckAuth();

  if (isLoading) return <Loading />;

  if (!isAuthenticated) {
    return <Navigate to="/login" replace />;
  }

  return children;
}

๋กœ๊ทธ์ธ ์•ˆ ํ–ˆ์œผ๋ฉด ์ฐจ๋‹จ

 

3. PublicRoute (๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ ๋ง‰๊ธฐ)

export default function PublicRoute({ children }) {
  const { isLoading, isAuthenticated } = useCheckAuth();

  if (isLoading) return <Loading />;

  if (isAuthenticated) {
    return <Navigate to="/home" replace />;
  }

  return children;
}

๋กœ๊ทธ์ธ ํ–ˆ์œผ๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ๋“ค์–ด๊ฐ€์ง€ ๋ชปํ•˜๊ฒŒ ๋ง‰๊ธฐ

 

4. Router ๊ตฌ์„ฑ

<Routes>
  {/* ๋กœ๊ทธ์ธ ์•ˆ ๋œ ์‚ฌ๋žŒ๋งŒ */}
  <Route
    path="/login"
    element={
      <PublicRoute>
        <Login />
      </PublicRoute>
    }
  />

  {/* ๋กœ๊ทธ์ธ ๋œ ์‚ฌ๋žŒ๋งŒ */}
  <Route
    path="/home"
    element={
      <ProtectedRoute>
        <Home />
      </ProtectedRoute>
    }
  />
</Routes>

 

5. ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ ์ด๋™ ์ฒ˜๋ฆฌ  

const handleLogin = async () => {
  const res = await loginApi();

  if (res.success) {
    navigate("/home");
  }
};

๐Ÿ‘‰ ์—ฌ๊ธฐ์„œ๋งŒ ์ด๋™ํ•œ๋‹ค

 

 

๋‚ด๊ฐ€ ํ–ˆ๋˜ ์‹ค์ˆ˜

๋‚ด๊ฐ€ ํ–ˆ๋˜ ์‹ค์ˆ˜๋ฅผ ์ •๋ฆฌํ•˜์ž๋ฉด

 

โŒ ProtectedRoute์—์„œ /home์œผ๋กœ ๋ณด๋‚ด๊ธฐ

์ด๊ฑด ์ ˆ๋Œ€ ํ•˜๋ฉด ์•ˆ ๋œ๋‹ค.

 

โŒ navigateTo + showChildren ๊ฐ™์ด ์“ฐ๊ธฐ

์ด ๊ฒฝ์šฐ ์ƒํƒœ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•œ๋‹ค.

 

โŒ ์ธ์ฆ ์„ฑ๊ณต ์‹œ redirect๋ฅผ ๊ฐ€๋“œ์—์„œ ์ฒ˜๋ฆฌ

์ด ๊ฒฝ์šฐ๋Š” ์ฑ…์ž„ ๋ถ„๋ฆฌ๊ฐ€ ๊นจ์ง„๋‹ค.

 

 

๊ฒฐ๋ก 

๋ผ์šฐํŒ…์€ ๋‹จ์ˆœํ•ด์•ผ ๋ฒ„๊ทธ๊ฐ€ ์—†๋‹ค.

  • ์ธ์ฆ ํ›… → ์ƒํƒœ๋งŒ ๋ฐ˜ํ™˜ํ•œ๋‹ค
  • ๋ผ์šฐํŠธ ๊ฐ€๋“œ → ๋ง‰๊ธฐ๋งŒ ํ•œ๋‹ค
  • ํŽ˜์ด์ง€ ์ด๋™ → ์ด๋ฒคํŠธ์—์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค

์ด 3๊ฐœ๋งŒ ์ง€์ผœ๋„ ๋กœ๊ทธ์ธ ํ”Œ๋กœ์šฐ๋Š” ๊ฑฐ์˜ ๊ผฌ์ด์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.