diff --git a/apps/web/src/app/(beforeLogin)/auth/token/page.tsx b/apps/web/src/app/(beforeLogin)/auth/token/page.tsx index ba48c01..dc8aee8 100644 --- a/apps/web/src/app/(beforeLogin)/auth/token/page.tsx +++ b/apps/web/src/app/(beforeLogin)/auth/token/page.tsx @@ -1,9 +1,8 @@ 'use client' -import { userInfoService } from '@vook-client/api' +import { userInfoService, UserStatus } from '@vook-client/api' import Cookies from 'js-cookie' import { useRouter } from 'next/navigation' -import { UserStatus } from 'node_modules/@vook-client/api/src/services/useUserInfoQuery/model' import { useEffect } from 'react' interface AuthCallbackQueryParams { diff --git a/apps/web/src/app/(beforeLogin)/signup/layout.tsx b/apps/web/src/app/(beforeLogin)/signup/layout.tsx index 3628692..cc7cf2f 100644 --- a/apps/web/src/app/(beforeLogin)/signup/layout.tsx +++ b/apps/web/src/app/(beforeLogin)/signup/layout.tsx @@ -1,4 +1,4 @@ -import React, { PropsWithChildren } from 'react' +import { PropsWithChildren } from 'react' import { loginLayout } from './layout.css' diff --git a/apps/web/src/middleware.ts b/apps/web/src/middleware.ts index ddb1dc2..7b4c0e2 100644 --- a/apps/web/src/middleware.ts +++ b/apps/web/src/middleware.ts @@ -1,85 +1,96 @@ import { NextRequest, NextResponse } from 'next/server' -import { UserInfoResponse, UserStatus } from 'node_modules/@vook-client/api/' +import { UserInfoResponse, UserStatus } from 'node_modules/@vook-client/api' -/** - * NOTE - * 1. 액세스 토큰과 리프레시 토큰이 모두 없는 경우 => 로그인 페이지로 리다이렉트 - * 2. 액세스 토큰만 있는 경우 => 로그인 페이지로 리다이렉트 - * 3. 리프레시 토큰만 있는 경우 => 리프레시 토큰으로 액세스 토큰을 갱신 - * 4. 액세스 토큰과 리프레시 토큰이 모두 있는 경우 => 액세스 토큰이 유효한지 확인 - */ +const checkUserStatusMiddleware = + (roles: Array) => + async ( + req: NextRequest, + finalResponse: NextResponse, + destination: string, + ) => { + const accessToken = req.cookies.get('access')?.value + const refreshToken = req.cookies.get('refresh')?.value -const onlyRegisteredMatch = ['/'] - -const isOnlyRegistered = async ( - req: NextRequest, - finalResponse: NextResponse, -) => { - const accessToken = req.cookies.get('access')?.value - const refreshToken = req.cookies.get('refresh')?.value - - // 1 & 2 - if ((!accessToken && !refreshToken) || (accessToken && !refreshToken)) { - return NextResponse.redirect(`${process.env.NEXT_PUBLIC_DOMAIN}/login`) - } + if ((!accessToken && !refreshToken) || (accessToken && !refreshToken)) { + return NextResponse.redirect( + `${process.env.NEXT_PUBLIC_DOMAIN}${destination}`, + ) + } - // 3 - if (!accessToken && refreshToken) { - const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/auth/refresh`, { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - 'X-Refresh-Authorization': refreshToken, - }, - }) - if ( - res.ok && - res.headers.get('Authorization') && - res.headers.get('X-Refresh-Authorization') - ) { - finalResponse.cookies.set('access', res.headers.get('Authorization')!) - finalResponse.cookies.set( - 'refresh', - res.headers.get('X-Refresh-Authorization')!, + if (!accessToken && refreshToken) { + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}/auth/refresh`, + { + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + 'X-Refresh-Authorization': refreshToken, + }, + }, ) - } else { - return NextResponse.redirect(`${process.env.NEXT_PUBLIC_DOMAIN}/login`) + if ( + res.ok && + res.headers.get('Authorization') && + res.headers.get('X-Refresh-Authorization') + ) { + finalResponse.cookies.set('access', res.headers.get('Authorization')!) + finalResponse.cookies.set( + 'refresh', + res.headers.get('X-Refresh-Authorization')!, + ) + } else { + return NextResponse.redirect( + `${process.env.NEXT_PUBLIC_DOMAIN}${destination}`, + ) + } } - } - const userInfoRes = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/user/info`, - { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - Authorization: - finalResponse.cookies.get('access')?.value || accessToken || '', + const userInfoRes = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}/user/info`, + { + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + Authorization: + finalResponse.cookies.get('access')?.value || accessToken || '', + }, }, - }, - ) + ) - if (userInfoRes.ok) { - const userInfo = (await userInfoRes.json()) as UserInfoResponse + if (userInfoRes.ok) { + const userInfo = (await userInfoRes.json()) as UserInfoResponse - // 회원가입이 완료되지 않은 경우 - if (userInfo.result.status === UserStatus.SocialLoginCompleted) { - return NextResponse.redirect(`${process.env.NEXT_PUBLIC_DOMAIN}/login`) + if (!roles.includes(userInfo.result.status)) { + return NextResponse.redirect( + `${process.env.NEXT_PUBLIC_DOMAIN}${destination}`, + ) + } else { + return finalResponse + } } else { - return finalResponse + return NextResponse.redirect( + `${process.env.NEXT_PUBLIC_DOMAIN}${destination}`, + ) } - } else { - return NextResponse.redirect(`${process.env.NEXT_PUBLIC_DOMAIN}/login`) } -} -// eslint-disable-next-line @typescript-eslint/require-await +const onlyRegisteredMatch = ['/'] + export async function middleware(req: NextRequest) { const response = NextResponse.next() if (onlyRegisteredMatch.includes(req.nextUrl.pathname)) { - await isOnlyRegistered(req, response) + return checkUserStatusMiddleware([ + UserStatus.Registered, + UserStatus.Withdrawn, + ])(req, response, '/login') } - return response + if (req.nextUrl.pathname === '/signup') { + return checkUserStatusMiddleware([UserStatus.SocialLoginCompleted])( + req, + response, + '/login', + ) + } }