import { createServerClient } from "@supabase/ssr"; import { NextResponse, type NextRequest } from "next/server"; /** * [미들웨어용 세션 업데이트 및 라우트 보호 함수] * * 이 함수는 모든 페이지 요청이 서버에 도달하기 전에 '가장 먼저' 실행됩니다. * * 주요 기능: * 1. 사용자의 로그인 토큰이 만료되었는지 확인하고, 만료되었다면 자동으로 갱신(Refresh) * 2. 인증 상태에 따라 접근 가능한 페이지를 제어 (라우트 보호) */ export async function updateSession(request: NextRequest) { // 1. 초기 응답 객체를 생성합니다. (그냥 통과시키는 기본 응답) let supabaseResponse = NextResponse.next({ request, }); // 2. 미들웨어 환경에서 동작하는 Supabase 클라이언트를 생성합니다. const supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: { // 요청(Request)에서 쿠키를 읽어옵니다. getAll() { return request.cookies.getAll(); }, // 쿠키를 저장/수정할 때 사용하는 로직입니다. setAll(cookiesToSet) { // (1) 요청(Request) 객체에도 쿠키를 업데이트해줍니다. (서버 컴포넌트가 최신 상태를 알도록) cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value), ); // (2) 응답(Response) 객체는 새로 만들어줍니다. supabaseResponse = NextResponse.next({ request, }); // (3) 최종 응답(Response)에 쿠키를 심어서 브라우저로 보냅니다. cookiesToSet.forEach(({ name, value, options }) => supabaseResponse.cookies.set(name, value, options), ); }, }, }, ); // 3. [핵심] 사용자의 인증 정보를 가져옵니다. // 이 함수를 호출하는 것만으로 Supabase는 만료된 토큰을 자동으로 '재발급(Refresh)' 합니다. // 재발급된 쿠키는 위 setAll 로직을 통해 Response에 담겨 브라우저로 전달됩니다. const { data: { user }, } = await supabase.auth.getUser(); console.log(user); // 4. [라우트 보호] 인증 상태에 따라 접근 제어 const { pathname } = request.nextUrl; // 4-1. 인증 관련 페이지 목록 (로그인하지 않아도 접근 가능) // 로그인, 회원가입, 비밀번호 찾기, 비밀번호 재설정 페이지 const authPages = [ "/login", "/signup", "/forgot-password", "/reset-password", ]; const isAuthPage = authPages.some((page) => pathname.startsWith(page)); // 4-2. 로그인하지 않은 사용자가 보호된 페이지에 접근하려는 경우 // → /login 페이지로 리다이렉트 if (!user && !isAuthPage) { const loginUrl = new URL("/login", request.url); return NextResponse.redirect(loginUrl); } // 4-3. 이미 로그인한 사용자가 인증 페이지(/login, /signup)에 접근하려는 경우 // → 메인 페이지(/)로 리다이렉트 (불필요한 접근 방지) // 단, /reset-password는 예외 (이메일 링크를 통한 비밀번호 재설정 허용) if (user && isAuthPage && pathname !== "/reset-password") { const homeUrl = new URL("/", request.url); return NextResponse.redirect(homeUrl); } // 5. 갱신된 쿠키가 담긴 응답을 반환하여 다음 단계(페이지 렌더링)로 넘어갑니다. return supabaseResponse; }