Skip to content

Commit

Permalink
refactor: 미들웨어 추상화
Browse files Browse the repository at this point in the history
  • Loading branch information
cobocho committed Jun 11, 2024
1 parent 69461cc commit 45777ec
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 67 deletions.
3 changes: 1 addition & 2 deletions apps/web/src/app/(beforeLogin)/auth/token/page.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/(beforeLogin)/signup/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { PropsWithChildren } from 'react'
import { PropsWithChildren } from 'react'

import { loginLayout } from './layout.css'

Expand Down
139 changes: 75 additions & 64 deletions apps/web/src/middleware.ts
Original file line number Diff line number Diff line change
@@ -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<UserStatus>) =>
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',
)
}
}

0 comments on commit 45777ec

Please sign in to comment.