From 04116b9bfbab2aa80a2d6fa1798e692bb681bfac Mon Sep 17 00:00:00 2001 From: S-Gihun <89789115+S-Gihun@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:07:51 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20feat:=20AuthWrapper=20=ED=86=B5?= =?UTF-8?q?=ED=95=B4=20=EA=B6=8C=ED=95=9C=20=EC=97=86=EC=9D=B4=20=EB=8B=A4?= =?UTF-8?q?=EB=A5=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A0=91=EA=B7=BC=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C=20#96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Auth/AuthWrapper.tsx | 30 +++++++++++ umc-master/src/router/routes.tsx | 54 ++++++++++++------- 2 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 umc-master/src/components/Auth/AuthWrapper.tsx diff --git a/umc-master/src/components/Auth/AuthWrapper.tsx b/umc-master/src/components/Auth/AuthWrapper.tsx new file mode 100644 index 0000000..933ab93 --- /dev/null +++ b/umc-master/src/components/Auth/AuthWrapper.tsx @@ -0,0 +1,30 @@ +import { useEffect } from 'react'; +import { useNavigate, useLocation } from 'react-router-dom'; +import { useTokenStore } from '@store/tokenStore'; +import RoutePaths from '@router/routePaths'; + +interface AuthWrapperProps { + children: React.ReactNode; +} + +const AuthWrapper = ({ children }: AuthWrapperProps) => { + const navigate = useNavigate(); + const location = useLocation(); + const { accessToken } = useTokenStore.getState(); + + useEffect(() => { + // 로그인 페이지가 아니고 토큰이 없는 경우 리다이렉트 + if (!accessToken && location.pathname !== RoutePaths.LANDING) { + navigate(RoutePaths.LOGIN, { replace: true }); + } + }, [accessToken, location.pathname, navigate]); + + // 토큰이 없고 로그인 페이지가 아닌 경우 아무것도 렌더링하지 않음 + if (!accessToken && location.pathname !== RoutePaths.LOGIN) { + return null; + } + + return <>{children}; +}; + +export default AuthWrapper; diff --git a/umc-master/src/router/routes.tsx b/umc-master/src/router/routes.tsx index d87d993..854b969 100644 --- a/umc-master/src/router/routes.tsx +++ b/umc-master/src/router/routes.tsx @@ -20,6 +20,39 @@ import ChatPage from '@pages/chat/ChatPage'; import ErrorPage from '@pages/error/ErrorPage'; import MyChallengePage from '@pages/mychallenge/MyChallenge'; import ChallengeDetailPage from '@pages/challenge/ChallengeDetailPage'; +import AuthWrapper from '@components/Auth/AuthWrapper'; + +// 인증이 필요한 라우트들을 배열로 정의 +const protectedRoutes = [ + { path: RoutePaths.MYPAGE, element: }, + { path: RoutePaths.MAIN, element: }, + { path: RoutePaths.SAVE_TIP, element: }, + { path: RoutePaths.SEARCH, element: }, + { path: RoutePaths.SAVE_TIP_DETAIL, element: }, + { path: RoutePaths.CREATE_POST, element: }, + { path: RoutePaths.COMMUNITY, element: }, + { path: RoutePaths.MAGAZINE, element: }, + { path: RoutePaths.MAGAZINE_DETAIL, element: }, + { path: RoutePaths.CHALLENGE, element: }, + { path: RoutePaths.MYCHALLENGE, element: }, + { path: RoutePaths.CHALLENGE_DETAIL, element: }, + { path: RoutePaths.CHAT, element: }, +]; + +// 인증이 필요없는 public 라우트들 +const publicRoutes = [ + { index: true, element: }, + { path: RoutePaths.LOGIN, element: }, + { path: RoutePaths.SIGNUP, element: }, + { path: RoutePaths.FINDPRIVACY, element: }, + { path: RoutePaths.KAKAO_CALLBACK, element: }, +]; + +// protected 라우트들을 AuthWrapper로 감싸기 +const wrappedProtectedRoutes = protectedRoutes.map((route) => ({ + ...route, + element: {route.element}, +})); const router = createBrowserRouter([ { @@ -28,26 +61,7 @@ const router = createBrowserRouter([ children: [ { errorElement: , - children: [ - { index: true, element: }, - { path: RoutePaths.LOGIN, element: }, - { path: RoutePaths.SIGNUP, element: }, - { path: RoutePaths.FINDPRIVACY, element: }, - { path: RoutePaths.MYPAGE, element: }, - { path: RoutePaths.MAIN, element: }, - { path: RoutePaths.SEARCH, element: }, - { path: RoutePaths.SAVE_TIP, element: }, - { path: RoutePaths.SAVE_TIP_DETAIL, element: }, - { path: RoutePaths.CREATE_POST, element: }, - { path: RoutePaths.COMMUNITY, element: }, - { path: RoutePaths.MAGAZINE, element: }, - { path: RoutePaths.MAGAZINE_DETAIL, element: }, - { path: RoutePaths.KAKAO_CALLBACK, element: }, - { path: RoutePaths.CHALLENGE, element: }, - { path: RoutePaths.MYCHALLENGE, element: }, - { path: RoutePaths.CHALLENGE_DETAIL, element: }, - { path: RoutePaths.CHAT, element: }, - ], + children: [...publicRoutes, ...wrappedProtectedRoutes], }, ], }, From 261c50f5fdc4be30c962a809b8bebee4e7760da1 Mon Sep 17 00:00:00 2001 From: S-Gihun <89789115+S-Gihun@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:08:42 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20=EC=8B=A4?= =?UTF-8?q?=EC=A0=9C=20accessToken=20=EC=9C=BC=EB=A1=9C=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=20#96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- umc-master/src/apis/axios-instance.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/umc-master/src/apis/axios-instance.ts b/umc-master/src/apis/axios-instance.ts index 6afb7ac..5add23a 100644 --- a/umc-master/src/apis/axios-instance.ts +++ b/umc-master/src/apis/axios-instance.ts @@ -1,11 +1,12 @@ -import RoutePaths from '@router/routePaths'; import { useTokenStore } from '@store/tokenStore'; import axios, { AxiosInstance } from 'axios'; +const { accessToken } = useTokenStore.getState(); + const axiosInstance: AxiosInstance = axios.create({ headers: { accept: 'application/json', - Authorization: `Bearer ${import.meta.env.VITE_ACCESS_TOKEN}`, + Authorization: `Bearer ${accessToken}`, }, baseURL: import.meta.env.VITE_BASE_URL, }); @@ -69,11 +70,6 @@ axiosInstance.interceptors.response.use( console.error('토큰 갱신 실패:', refreshError); useTokenStore.getState().clearTokens(); - // 로그인 페이지로 리다이렉트 - if (window.location.pathname !== RoutePaths.LOGIN) { - window.location.href = RoutePaths.LOGIN; - } - return Promise.reject(refreshError); } } From 9c511be1fe32d6118fca26d00b9514cf8a37876b Mon Sep 17 00:00:00 2001 From: S-Gihun <89789115+S-Gihun@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:12:38 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20refreshTok?= =?UTF-8?q?en=20Default=20=EA=B0=92=20null=20=EC=84=A4=EC=A0=95=20#96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- umc-master/src/store/tokenStore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/umc-master/src/store/tokenStore.ts b/umc-master/src/store/tokenStore.ts index 3f894cc..b06adaf 100644 --- a/umc-master/src/store/tokenStore.ts +++ b/umc-master/src/store/tokenStore.ts @@ -9,7 +9,7 @@ interface TokenStore { export const useTokenStore = create((set) => ({ accessToken: null, - refreshToken: `${import.meta.env.VITE_REFRESH_TOKEN}` /* 로그인 기능 완성 후 수정 예정임 */, + refreshToken: null /* 로그인 기능 완성 후 수정 예정임 */, setTokens: (tokens) => { // console.log('Setting Tokens:', tokens); set(() => ({