From d7807383ac17cc734f79eeecfd3e0a55dd343fa0 Mon Sep 17 00:00:00 2001 From: ylem76 Date: Sat, 17 Aug 2024 13:56:44 +0900 Subject: [PATCH 1/8] [#206] add server actions --- src/app/login/components/LoginForm.tsx | 42 +++++++++++++++----------- src/app/login/loginAction.tsx | 17 +++++++++++ 2 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 src/app/login/loginAction.tsx diff --git a/src/app/login/components/LoginForm.tsx b/src/app/login/components/LoginForm.tsx index 21fcf01..5ad0a8a 100644 --- a/src/app/login/components/LoginForm.tsx +++ b/src/app/login/components/LoginForm.tsx @@ -13,6 +13,8 @@ import { getDashboardList } from '@/lib/dashboardsApi' import useDashboardStore from '@/store/useDashboardStore' import useModalStore from '@/store/useModalStore' +import loginAction from '../loginAction' + export interface LoginFormValue { email: string password: string @@ -29,6 +31,7 @@ export default function LoginForm() { } = useForm() const router = useRouter() + const { openModal } = useModalStore() const { setDashboards } = useDashboardStore() @@ -36,24 +39,27 @@ export default function LoginForm() { const passwordType = pwdVisible ? 'text' : 'password' const onSubmit = async (data: LoginFormValue) => { - try { - const response = await api.post('auth/login', data) - const { accessToken, user } = response.data - sessionStorage.setItem('accessToken', accessToken) - sessionStorage.setItem('user', JSON.stringify(user)) - const dashboards = await getDashboardList() - setDashboards(dashboards) - router.push('/mydashboard') - } catch (error) { - let loginErrorMessage = '' - if (axios.isAxiosError(error)) { - loginErrorMessage = error.response?.data.message - } else { - loginErrorMessage = - '서버에 문제가 있는거 같아요. 잠시 후에 다시 시도해보시겠어요?' - } - openModal() - } + // 로그인 액션 실행 + console.log(data) + loginAction(data) + // try { + // const response = await api.post('auth/login', data) + // const { accessToken, user } = response.data + // sessionStorage.setItem('accessToken', accessToken) + // sessionStorage.setItem('user', JSON.stringify(user)) + // const dashboards = await getDashboardList() + // setDashboards(dashboards) + // router.push('/mydashboard') + // } catch (error) { + // let loginErrorMessage = '' + // if (axios.isAxiosError(error)) { + // loginErrorMessage = error.response?.data.message + // } else { + // loginErrorMessage = + // '서버에 문제가 있는거 같아요. 잠시 후에 다시 시도해보시겠어요?' + // } + // openModal() + // } } const isDisabled = !!(errors.email || errors.password || isLoading) diff --git a/src/app/login/loginAction.tsx b/src/app/login/loginAction.tsx new file mode 100644 index 0000000..7d7d208 --- /dev/null +++ b/src/app/login/loginAction.tsx @@ -0,0 +1,17 @@ +'use server' + +import { cookies } from 'next/headers' +import { redirect } from 'next/navigation' + +import api from '@/lib/axiosInstance' + +import { LoginFormValue } from './components/LoginForm' + +export default async function loginAction(data: LoginFormValue) { + // 폼에서 데이터 가져오기 = data + // 백엔드 요청 + // 가져온 json token 쿠키 설정 하기 + // 로그인 여부에 따라 redirect + + return { message: 'test' } +} From 1996a70506ef201360aa7ad692723ff84069801a Mon Sep 17 00:00:00 2001 From: ylem76 Date: Sat, 17 Aug 2024 14:46:47 +0900 Subject: [PATCH 2/8] =?UTF-8?q?[#206]=20login=20action=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/login/components/LoginForm.tsx | 26 +++++-------------- src/app/login/loginAction.tsx | 35 +++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/app/login/components/LoginForm.tsx b/src/app/login/components/LoginForm.tsx index 5ad0a8a..696d77f 100644 --- a/src/app/login/components/LoginForm.tsx +++ b/src/app/login/components/LoginForm.tsx @@ -40,26 +40,12 @@ export default function LoginForm() { const onSubmit = async (data: LoginFormValue) => { // 로그인 액션 실행 - console.log(data) - loginAction(data) - // try { - // const response = await api.post('auth/login', data) - // const { accessToken, user } = response.data - // sessionStorage.setItem('accessToken', accessToken) - // sessionStorage.setItem('user', JSON.stringify(user)) - // const dashboards = await getDashboardList() - // setDashboards(dashboards) - // router.push('/mydashboard') - // } catch (error) { - // let loginErrorMessage = '' - // if (axios.isAxiosError(error)) { - // loginErrorMessage = error.response?.data.message - // } else { - // loginErrorMessage = - // '서버에 문제가 있는거 같아요. 잠시 후에 다시 시도해보시겠어요?' - // } - // openModal() - // } + const errMsg = await loginAction(data) + + // 에러 메시지 팝업 + if (errMsg) { + openModal() + } } const isDisabled = !!(errors.email || errors.password || isLoading) diff --git a/src/app/login/loginAction.tsx b/src/app/login/loginAction.tsx index 7d7d208..0976c66 100644 --- a/src/app/login/loginAction.tsx +++ b/src/app/login/loginAction.tsx @@ -8,10 +8,37 @@ import api from '@/lib/axiosInstance' import { LoginFormValue } from './components/LoginForm' export default async function loginAction(data: LoginFormValue) { - // 폼에서 데이터 가져오기 = data // 백엔드 요청 - // 가져온 json token 쿠키 설정 하기 - // 로그인 여부에 따라 redirect + try { + const response = await fetch( + 'https://sp-taskify-api.vercel.app/7-2/auth/login', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + } + ) + + const responsedData = await response.json() + if (responsedData.message) { + throw new Error(responsedData.message) + } + const { accessToken, user } = responsedData - return { message: 'test' } + // 가져온 json token 쿠키 설정 하기 + cookies().set('Authorization', accessToken, { + secure: true, + httpOnly: true, + expires: Date.now() + 24 * 60 * 60 * 1000 * 3, + path: '/', + sameSite: 'strict', + }) + } catch (error: any) { + return error.message + } + + // 로그인 여부에 따라 redirect + redirect('/mydashboard') } From 9244507f3b35a003b26a68e6748d2abaf88e8826 Mon Sep 17 00:00:00 2001 From: ylem76 Date: Sat, 17 Aug 2024 15:22:14 +0900 Subject: [PATCH 3/8] =?UTF-8?q?[#206]=20axios=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/login/loginAction.tsx | 23 ++++------------------- src/lib/axiosInstance.ts | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/app/login/loginAction.tsx b/src/app/login/loginAction.tsx index 0976c66..263ba1f 100644 --- a/src/app/login/loginAction.tsx +++ b/src/app/login/loginAction.tsx @@ -1,5 +1,4 @@ 'use server' - import { cookies } from 'next/headers' import { redirect } from 'next/navigation' @@ -10,33 +9,19 @@ import { LoginFormValue } from './components/LoginForm' export default async function loginAction(data: LoginFormValue) { // 백엔드 요청 try { - const response = await fetch( - 'https://sp-taskify-api.vercel.app/7-2/auth/login', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(data), - } - ) - - const responsedData = await response.json() - if (responsedData.message) { - throw new Error(responsedData.message) - } - const { accessToken, user } = responsedData + const response = await api.post('/auth/login', data, {}) + const { accessToken, user } = response.data // 가져온 json token 쿠키 설정 하기 cookies().set('Authorization', accessToken, { secure: true, httpOnly: true, - expires: Date.now() + 24 * 60 * 60 * 1000 * 3, + expires: new Date(Date.now() + 24 * 60 * 60 * 1000 * 3), path: '/', sameSite: 'strict', }) } catch (error: any) { - return error.message + return error.response?.data?.message || error.message } // 로그인 여부에 따라 redirect diff --git a/src/lib/axiosInstance.ts b/src/lib/axiosInstance.ts index 65df261..09c3d87 100644 --- a/src/lib/axiosInstance.ts +++ b/src/lib/axiosInstance.ts @@ -15,17 +15,17 @@ export const setAccessToken = (token: string) => { accessToken = token } -api.interceptors.request.use( - config => { - const token = sessionStorage.getItem('accessToken') - if (token) { - config.headers.Authorization = `Bearer ${token}` - } - return config - }, - error => { - return Promise.reject(error) - } -) +// api.interceptors.request.use( +// config => { +// const token = sessionStorage.getItem('accessToken') +// if (token) { +// config.headers.Authorization = `Bearer ${token}` +// } +// return config +// }, +// error => { +// return Promise.reject(error) +// } +// ) export default api From 6eb527bf41e297c6c012c4995d64e96c549a5335 Mon Sep 17 00:00:00 2001 From: ylem76 Date: Sat, 17 Aug 2024 15:28:41 +0900 Subject: [PATCH 4/8] =?UTF-8?q?[#206]=20middleware=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/middleware.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/middleware.ts diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..edb8a8f --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,15 @@ +import { cookies } from 'next/headers' +import type { NextRequest } from 'next/server' +import { NextResponse } from 'next/server' + +export async function middleware(request: NextRequest) { + // 쿠키 확인 + const cookie = cookies().get('Authorization') + if (!cookie) { + return NextResponse.redirect(new URL('/login', request.url)) + } +} + +export const config = { + matcher: ['/mydashboard/:path*', '/dashboard/:path*', '/mypage/:path*'], +} From 4eef97d4465d8c54161f92146277a15ed0a3133e Mon Sep 17 00:00:00 2001 From: ylem76 Date: Sat, 17 Aug 2024 15:58:50 +0900 Subject: [PATCH 5/8] =?UTF-8?q?[#206]=20axios=20server=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/login/loginAction.tsx | 6 +++--- src/lib/axiosInstance.ts | 37 +++++++++++++++++++---------------- src/lib/axiosServer.ts | 29 +++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 src/lib/axiosServer.ts diff --git a/src/app/login/loginAction.tsx b/src/app/login/loginAction.tsx index 263ba1f..e576ac6 100644 --- a/src/app/login/loginAction.tsx +++ b/src/app/login/loginAction.tsx @@ -2,7 +2,7 @@ import { cookies } from 'next/headers' import { redirect } from 'next/navigation' -import api from '@/lib/axiosInstance' +import api from '@/lib/axiosServer' import { LoginFormValue } from './components/LoginForm' @@ -15,9 +15,9 @@ export default async function loginAction(data: LoginFormValue) { // 가져온 json token 쿠키 설정 하기 cookies().set('Authorization', accessToken, { secure: true, - httpOnly: true, + // httpOnly: true, expires: new Date(Date.now() + 24 * 60 * 60 * 1000 * 3), - path: '/', + // path: '/', sameSite: 'strict', }) } catch (error: any) { diff --git a/src/lib/axiosInstance.ts b/src/lib/axiosInstance.ts index 09c3d87..190f422 100644 --- a/src/lib/axiosInstance.ts +++ b/src/lib/axiosInstance.ts @@ -6,26 +6,29 @@ const api = axios.create({ 'Content-Type': 'application/json', }, // withCredentials: true, - // timeout: 10000, // 요청 제한 시간 설정 (밀리초) }) -let accessToken: string = '' +api.interceptors.request.use( + config => { + function getCookie(name: string) { + const value = `; ${document.cookie}` + const parts = value.split(`; ${name}=`) -export const setAccessToken = (token: string) => { - accessToken = token -} + if (parts) { + return parts[1].split(';').shift() + } + } -// api.interceptors.request.use( -// config => { -// const token = sessionStorage.getItem('accessToken') -// if (token) { -// config.headers.Authorization = `Bearer ${token}` -// } -// return config -// }, -// error => { -// return Promise.reject(error) -// } -// ) + const token = getCookie('Authorization') + console.log(token) + if (token) { + config.headers.Authorization = `Bearer ${token}` + } + return config + }, + error => { + return Promise.reject(error) + } +) export default api diff --git a/src/lib/axiosServer.ts b/src/lib/axiosServer.ts new file mode 100644 index 0000000..0adf225 --- /dev/null +++ b/src/lib/axiosServer.ts @@ -0,0 +1,29 @@ +'use server' + +import axios from 'axios' +import { cookies } from 'next/headers' + +const api = axios.create({ + baseURL: 'https://sp-taskify-api.vercel.app/7-2', + headers: { + 'Content-Type': 'application/json', + }, + withCredentials: true, +}) + +api.interceptors.request.use( + config => { + console.log('interceptor') + const token = cookies().get('Authorization') + + if (token) { + config.headers.Authorization = `Bearer ${token}` + } + return config + }, + error => { + return Promise.reject(error) + } +) + +export default api From 300e0b3e890267b91ab5fbdd5d0e5c07de136996 Mon Sep 17 00:00:00 2001 From: ylem76 Date: Sat, 17 Aug 2024 15:59:08 +0900 Subject: [PATCH 6/8] [#206] remove useRedirect --- src/app/dashboard/layout.tsx | 2 +- src/app/mydashboard/page.tsx | 2 +- src/app/mypage/page.tsx | 2 +- src/app/page.tsx | 2 +- src/app/signup/page.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx index 24c81d4..cf83a32 100644 --- a/src/app/dashboard/layout.tsx +++ b/src/app/dashboard/layout.tsx @@ -13,7 +13,7 @@ import useDashboardStore from '@/store/useDashboardStore' * 주스탠드에 저장된 대시보드 목록에서 dashboardid 로 title 가져올 수 잇을 듯 */ export default function UserDashboardLayout({ children }: PropsWithChildren) { - useRedirect({ requireAuth: true }) + // useRedirect({ requireAuth: true }) const { id } = useParams() const { dashboards, dashboard, setDashboard } = useDashboardStore() diff --git a/src/app/mydashboard/page.tsx b/src/app/mydashboard/page.tsx index 0b0a2c6..bbf22fc 100644 --- a/src/app/mydashboard/page.tsx +++ b/src/app/mydashboard/page.tsx @@ -18,7 +18,7 @@ type PaginationAction = 'prev' | 'next' const ITEM_PER_PAGE = 5 export default function MyDashboard() { - useRedirect({ requireAuth: true }) + // useRedirect({ requireAuth: true }) const { openModal } = useModalStore() const { dashboards } = useDashboardStore() diff --git a/src/app/mypage/page.tsx b/src/app/mypage/page.tsx index c6b4d29..b2da594 100644 --- a/src/app/mypage/page.tsx +++ b/src/app/mypage/page.tsx @@ -7,7 +7,7 @@ import PasswordEditForm from './components/PasswordEditForm' import ProfileEditForm from './components/ProfileEditForm' export default function MyPagePage() { - useRedirect({ requireAuth: true }) + // useRedirect({ requireAuth: true }) const handleGoBack = useGoBack() diff --git a/src/app/page.tsx b/src/app/page.tsx index c7639a6..4e48ce0 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -6,7 +6,7 @@ import useRedirect from '@/hooks/useRedirect' import { Providers } from './providers' export default function Home() { - useRedirect({ requireAuth: false }) + // useRedirect({ requireAuth: false }) return ( <> diff --git a/src/app/signup/page.tsx b/src/app/signup/page.tsx index f78928d..7951d18 100644 --- a/src/app/signup/page.tsx +++ b/src/app/signup/page.tsx @@ -5,7 +5,7 @@ import useRedirect from '@/hooks/useRedirect' import AuthPageLayout from '@/layouts/AuthPageLayout' export default function SignupPage() { - useRedirect({ requireAuth: false }) + // useRedirect({ requireAuth: false }) return ( From fdb24f57f29373d298d8f539588972ffc8cd9b03 Mon Sep 17 00:00:00 2001 From: ylem76 Date: Sat, 17 Aug 2024 16:03:40 +0900 Subject: [PATCH 7/8] =?UTF-8?q?[#206]=20=EB=AF=B8=EB=93=A4=EC=9B=A8?= =?UTF-8?q?=EC=96=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/middleware.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/middleware.ts b/src/middleware.ts index edb8a8f..f200c39 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -8,8 +8,12 @@ export async function middleware(request: NextRequest) { if (!cookie) { return NextResponse.redirect(new URL('/login', request.url)) } + + if (cookie && request.nextUrl.pathname === '/') { + return NextResponse.redirect(new URL('/mydashboard', request.url)) + } } export const config = { - matcher: ['/mydashboard/:path*', '/dashboard/:path*', '/mypage/:path*'], + matcher: ['/', '/mydashboard/:path*', '/dashboard/:path*', '/mypage/:path*'], } From 2a345462c4823139126a70a98f978de512690d23 Mon Sep 17 00:00:00 2001 From: ylem76 Date: Sat, 17 Aug 2024 16:14:12 +0900 Subject: [PATCH 8/8] [#206] add user data --- src/components/UserProfile.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/UserProfile.tsx b/src/components/UserProfile.tsx index ff2fd5c..a4cca4a 100644 --- a/src/components/UserProfile.tsx +++ b/src/components/UserProfile.tsx @@ -18,6 +18,7 @@ export default function UserProfile() { try { const response = await api.get('users/me') setUser(response.data) + sessionStorage.setItem('user', response.data) } catch (error) { throw error } @@ -31,6 +32,8 @@ export default function UserProfile() { router.push('/login') setUser(null) sessionStorage.clear() + + document.cookie = `Authorization=; Max-Age=-99999999;` } useEffect(() => {