๐ Task TODOLIST
- [x] middleware ๋ฅผ ํตํ ๋ผ์ฐํธ ๋ณดํธ
- [x] ์ฌ๋ฌ ๋ผ์ฐํธ ๋ณดํธ๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ chain ๋ง๋ค๊ธฐ
โจ ๊ฐ๋ฐ ๋ด์ฉ
Why(์ด์ ) ?
์ปดํฌ๋ํธ ๋จ์์ ๋ผ์ฐํธ ๋ณดํธ๋ฅผ ํ ์ง(ex. (auth) / (nonAuth) ๋ก ํด๋๋ฅผ ๋๋์ด์),
middleware์์ ๋ผ์ฐํธ ๋ณดํธ๋ฅผ ํ ์ง ํ์๋ค์ด๋ ์์๋ฅผ ํ๋๋ฐ ๋ฏธ๋ค์จ์ด๊ฐ ๋น์ฒจ๋๋ค.
์ด์ ๋
1. ์ผ๋จ ๊ฐ ์ปดํฌ๋ํธ์์ ์จ์ผ ํ ๋ณด์ผ๋ฌ ํ๋ ์ดํธ๊ฐ ์ค์ด๋ ๋ค!
๊ถํ์ด ์์ผ๋ฉด router.push๋ฅผ ํด์ฃผ์ด์ผ ํ๋ค๋ ์ง,
alert("๋ก๊ทธ์ธ ํ ์ด์ฉ๊ฐ๋ฅ ํฉ๋๋ค") ๋ฑ์ alert๋ฅผ ๋งค ์ปดํฌ๋ํธ๋ค์์ ๋ง๋ค ์ฒ๋ฆฌ๋ฅผ ํด์ค์ผ ํ๋ ๊ฒ์
๋ฏธ๋ค์จ์ด์์ ์์ ์ ๊ทผํ์ง ๋ชปํ๊ฒ ์ฒ๋ฆฌํ๊ธฐ๋ก ํ๋ค.
2. ์ด๋ฒ ๊ธฐํ๋ก middleware๋ฅผ ์ ๋๋ก ํ์ฉํด๋ณด๊ณ ์ถ์๋ค.
How(๊ณผ์ ) && what(๊ฒฐ๊ณผ)
(1) ์ด๋ค ์กฐ๊ฑด์ผ๋ก ๊ฐ ๋ผ์ฐํธ๋ฅผ ๋ณดํธํ ์ง ๊ฒฐ์ ํ๋ค.
์ฐ๋ฆฌ ํ์ ์ด 5๊ฐ์ ๋ฏธ๋ค์จ์ด๊ฐ ํ์ํ๋ค.
<์ธ์ ์ ๋ฐ์ดํธ / ๋ก๊ทธ์ธ ์ฌ๋ถ / ๋ด๊ฐ ์ฐธ์ฌ์ค์ธ ๋ฏธํ ๋ฐฉ๋ง / ๋ด๊ฐ ์ฐธ์ฌ์ค์ธ ์ฑํ ๋ฐฉ๋ง / ํ๊ต์ธ์ฆ ์ฌ๋ถ>
์ ๋ฐ๋ผ์ ๋ผ์ฐํธ ๋ณดํธ๊ฐ ํ์ํ๋ค.
// ์ธ์
์
๋ฐ์ดํธ
export const updateSessionMiddleware = (middleware: CustomMiddleware) => {
return async (request: NextRequest, event: NextFetchEvent) => {
await updateSession(request);
return middleware(request, event, NextResponse.next());
};
};
// ๋ก๊ทธ์ธ ์ฌ๋ถ
export const routeHandlerMiddleware = (middleware: CustomMiddleware) => {
return async (request: NextRequest, event: NextFetchEvent, response: NextResponse) => {
const supabase = serverSupabase();
const { data } = await supabase.auth.getUser();
if (data.user) {
// ๋ก๊ทธ์ธ ํ ์ ์
if (request.nextUrl.pathname.startsWith('/login')) {
return NextResponse.redirect(new URL('/', request.nextUrl.origin));
} else if (request.nextUrl.pathname.startsWith('/join')) {
return NextResponse.redirect(new URL('/', request.nextUrl.origin));
}
} else {
// ๋ก๊ทธ์ธ ์ํ ์ ์
if (request.nextUrl.pathname.startsWith('/mypage')) {
// ๋ง์ดํ์ด์ง ์ ๊ทผ ๋ฐฉ์ง + ๋ก๊ทธ์ธ ํ์ด์ง๋ก redirect
return NextResponse.redirect(new URL('/login', request.url));
} else if (request.nextUrl.pathname.startsWith('/meetingRoom') || request.nextUrl.pathname.startsWith('/chat/')) {
// ๋ก๋น๋ก ์ ๊ทผ ๋ถ๊ฐ
return NextResponse.redirect(new URL('/login', request.url));
}
}
return middleware(request, event, response);
};
};
export const chatRoomHandler = (middleware: CustomMiddleware) => {
return async (request: NextRequest, event: NextFetchEvent, response: NextResponse) => {
// ์ฑํ
์ฐฝ
if (request.nextUrl.pathname.startsWith('/chat/')) {
const supabase = serverSupabase();
const {
data: { user }
} = await supabase.auth.getUser();
// ๋ด๊ฐ ๋ค์ด๊ฐ์๋ ๋ฐฉ๋ค
const myChatRooms = [];
const { data: myRooms } = await supabase
.from('participants')
.select('room_id')
.eq('user_id', String(user?.id))
.eq('isDeleted', false);
if (myRooms) {
for (let room of myRooms) {
const { data: myChatRoomId } = await supabase
.from('chatting_room')
.select('chatting_room_id')
.eq('room_id', room.room_id)
.eq('isActive', true);
if (myChatRoomId && myChatRoomId.length) {
myChatRooms.push(myChatRoomId[0].chatting_room_id);
}
}
if (myChatRooms.includes(request.nextUrl.pathname.replace('/chat/', ''))) {
// ๋ด๊ฐ ๋ค์ด๊ฐ์๋ ๋ฐฉ์ด๋ฉด OK
return NextResponse.next();
} else {
// ๋ด๊ฐ ๋ค์ด๊ฐ์๋ ๋ฐฉ์ด ์๋๋ฉด ๋ก๋น๋ก
return NextResponse.redirect(new URL('/meetingRoom', request.nextUrl.origin));
}
}
}
return middleware(request, event, NextResponse.next());
};
};
export const meetingRoomHandler = (middleware: CustomMiddleware) => {
return async (request: NextRequest, event: NextFetchEvent, response: NextResponse) => {
// ์๋ฝ์ฐฝ
if (request.nextUrl.pathname.startsWith('/meetingRoom/')) {
const supabase = serverSupabase();
const {
data: { user }
} = await supabase.auth.getUser();
// ๋ด๊ฐ ๋ค์ด๊ฐ์๋ ๋ฐฉ๋ค
const { data: myRooms } = await supabase
.from('participants')
.select('room_id')
.eq('user_id', String(user?.id))
.eq('isDeleted', false);
if (
myRooms &&
myRooms.map((room) => room.room_id).includes(request.nextUrl.pathname.replace('/meetingRoom/', ''))
) {
return NextResponse.next();
} else {
return NextResponse.redirect(new URL('/', request.nextUrl.origin));
}
}
return middleware(request, event, NextResponse.next());
};
};
// ํ๊ต์ธ์ฆ์ฌ๋ถ
export const schoolValidateMiddleware = (middleware: CustomMiddleware) => {
return async (request: NextRequest, event: NextFetchEvent, response: NextResponse) => {
if (request.nextUrl.pathname.startsWith('/meetingRoom')) {
const supabase = serverSupabase();
const { data } = await supabase.auth.getUser();
const { data: isValidate } = await supabase
.from('users')
.select('isValidate')
.eq('user_id', data.user?.id as string);
if (isValidate && !isValidate[0].isValidate) {
return NextResponse.redirect(new URL('/mypage', request.url));
}
}
return middleware(request, event, NextResponse.next());
};
};
(2) ๋ฏธ๋ค์จ์ด ์ข ๋ฅ๊ฐ 5๊ฐ ์ด๋ ํ๋์ middleware.ts ํ์ผ์ ์ฐ๊ฒจ๋ฃ๊ธฐ ๋ณด๋ค๋ multiple middleware๋ฅผ chain์ ํตํด ์ฌ๊ทํจ์๋ก ๋ง๋ค์ด๋ณธ๋ค.
// chain.ts
import { NextFetchEvent, NextRequest, NextResponse } from 'next/server';
import { CustomMiddleware } from './middlewareType';
type MiddlewareFactory = (middleware: CustomMiddleware) => CustomMiddleware;
export const chain = (functions: MiddlewareFactory[], index = 0): CustomMiddleware => {
const current = functions[index];
if (current) {
const next = chain(functions, index + 1);
return current(next);
// current(chain(functions, 1)) => current(current(chain(functions,2))) => current(current(chain(functions,3)))
// ์ด๋ฐ ์์ผ๋ก chain์ด ํ์ฑ๋๊ณ , ์ฌ๊ทํจ์ ์คํ
}
// ๋ง์ง๋ง ์์์ผ ๋
return async (request: NextRequest, event: NextFetchEvent, response: NextResponse) => {
return response;
};
};
(3) middleware.ts์์ ํ๋์ chain์ผ๋ก ์ฎ์ด์ค๋ค.
// src > middleware.ts
const middlewareList = [
updateSessionMiddleware,
routeHandlerMiddleware,
schoolValidateMiddleware,
meetingRoomHandler,
chatRoomHandler
];
export default chain(middlewareList);
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)']
};
๐จ TroubleShotting && ๐ธ ์คํฌ๋ฆฐ์ท
์๋ ํ๊ต์ธ์ฆ์ฌ๋ถ middleware๋ ํ๊ต์ธ์ฆ์ฌ๋ถ๋ฅผ ๋ค์ ๋ฏธ๋ค์จ์ด์ header์ boolean ๊ฐ์ ์ฌ๊ณ , | ๋ค์ ๋ฏธ๋ค์จ์ด์์ ์ฌ์ด์ง ํค๋์์ get ํด์ ๋ผ์ฐํธ ๋ณดํธ๋ฅผ ํ๋ ค๊ณ ํ๋ค. |
๊ทผ๋ฐ ๋ฐ๋ ๋ฏธ๋ค์จ์ด์์ get์ด ์ ๋๋ ๊ฒ์ด๋ค..!!
๊ทผ๋ฐ ๋ฒ๊ทธ์ธ ๊ฑฐ ๊ฐ๋ค..
์ ๋ฒ๊ทธ๋ผ ํ๋๋ฉด, chain์ผ๋ก ์ฎ์ง ์๊ณ ์ผ๋ฐ middleware๋ก ํ๋ฉด header๊ฐ ์ get ๋๋ค.
ํ์ง๋ง chain๋ง ์ฎ์ผ๋ฉด header๊ฐ ์์ด์ง๋...Bug....
์ฐพ์๋ณด๋ ๋ค๋ฅธ ์ฌ๋๋ค๋ middleware ์ฒด์ธ์์ header์ ์ฌ์ ๊ฒ์ ๋ค์ ๋ฏธ๋ค์จ์ด์์ ํ์ธํ ์ ์๋ค๋ ๊ธ๋ค์ด ๋ง์๋ค.
https://github.com/traefik/traefik/issues/5890
=> ํ์ฌ header์ ์ฌ๋ ๋ฐฉ๋ฒ์ pass!
๋ฐ๋ก ๋ฆฌ๋๋ ์ ์ ์์ผ์ค๋ฒ๋ ธ๋ค.
๐ ๋ ํผ๋ฐ์ค
https://www.youtube.com/watch?v=fmFYH_Xu3d0&list=PL1lHTvxfWQGoJ6IornrxP0rwUV8m_iluA&index=2
https://github.com/Team-MeetGo/MeetGO/pull/86
https://github.com/Team-MeetGo/MeetGO/pull/127