Next.js + Supabase 프로젝트 - (4) : Supabase 연결 - 코드 구현

Next.js + Supabase 프로젝트 - (4) : Supabase 연결 - 코드 구현

📅
nuleonginuleongi
5
#Nextjs Supabase#Nextjs Supabase 코드 설정#Nextjs Supabase 연동#Nextjs client.ts#Nextjs server.ts#Supabase 브라우저 클라이언트#Supabase 서버 클라이언트#Supabase admin client#Nextjs 풀스택#Nextjs 프로젝트 설정#Supabase 설정 방법#Nextjs Supabase 튜토리얼#웹개발 가이드#Supabase Typescript#Nextjs 개발 팁
💡이 글의 요약

이 글은 "Next.js + Supabase 프로젝트" 시리즈의 네 번째 글로, 브라우저와 서버 환경에서 각각 Supabase 클라이언트를 설정하는 방법을 상세히 안내합니다. utils/supabase/client.ts에서는 createBrowserSupabaseClient()를 통해 익명 키 기반 브라우저 클라이언트를 생성하고, utils/supabase/server.ts에서는 쿠키 관리와 함께 서버용 클라이언트를 사용하거나 관리(admin) 권한 클라이언트를 만드는 방법을 설명합니다

Supabase 의 기능을 사용할 코드를 작성할 텐데, 두 가지로 나누어서 구현하려고 합니다.

 

1) Supabase 의 client 기능

2) Supabase 의 server 기능

 

app 폴더 밖의 root 폴더에 utils 폴더를 만들고

그 안에 supabase 폴더를 만들고, 이 안에 파일들을 생성할 예정입니다

 

utils/supabase/client.ts

  • 목적: 브라우저 환경에서 Supabase 클라이언트를 생성하기 위한 함수

  • 주요 기능:

    • createBrowserSupabaseClient(): 브라우저에서 사용할 Supabase 클라이언트를 생성합니다. Supabase의 URL과 익명 키를 환경 변수에서 읽어옵니다.

"use client";

import { createBrowserClient } from "@supabase/ssr";

// 내 supabase 프로젝트랑 연관된 이 api를 통해서 anon key를 통해서 브라우저 클라이언트가 하나 자동으로 생성이 된다.
export const createBrowserSupabaseClient = () =>
    createBrowserClient(
        process.env.NEXT_PUBLIC_SUPABASE_URL!,
        process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
    );

 

utils/supabase/server.ts

  • 목적: 서버 환경에서 Supabase 클라이언트를 생성하기 위한 함수들

  • 주요 기능:

    • createServerSupabaseClient(): 서버에서 사용할 Supabase 클라이언트를 생성합니다. 환경 변수에서 Supabase의 URL과, 주어진 권한에 따라 비공식 또는 관리 권한 키를 사용합니다. 쿠키 관리 기능도 포함되어 있습니다.

    • createServerSupabaseAdminClient(): 관리 권한을 가진 Supabase 클라이언트를 생성합니다. 서버 측에서만 호출되며, admin 플래그를 true로 설정하여 관리 키를 사용합니다.

"use server";

import { createServerClient, type CookieOptions } from "@supabase/ssr";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
import { Database } from "../../types_db";

// 서버 컴포넌트들에서만 사용을 할 거임
export const createServerSupabaseClient = async (
    cookieStore?: Awaited<ReturnType<typeof cookies>>,
    admin: boolean = false
) => {
    const resolvedCookieStore = cookieStore || await cookies();
    return createServerClient<Database>(
        process.env.NEXT_PUBLIC_SUPABASE_URL!,
        admin
            ? process.env.NEXT_SUPABASE_SERVICE_ROLE!
            : process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
        {
            // 쿠기 get, set, remove 하는 부분 설정을 해줘야
            // 이제 유저 관련된 오퍼레이션들이 전부 동작을 함. 인증 부분 구축을 할 때에 많이 사용을 하게 될 거임.
            // supabase 에 다 나와있긴 한데, 좀 복잡하니 이거 사용
            cookies: {
                get(name: string) {
                    return resolvedCookieStore.get(name)?.value;
                },
                set(name: string, value: string, options: CookieOptions) {
                    try {
                        resolvedCookieStore.set({ name, value, ...options });
                    } catch (error) {
                        // The `set` method was called from a Server Component.
                        // This can be ignored if you have middleware refreshing
                        // user sessions.
                    }
                },
                remove(name: string, options: CookieOptions) {
                    try {
                        resolvedCookieStore.set({ name, value: "", ...options });
                    } catch (error) {
                        // The `delete` method was called from a Server Component.
                        // This can be ignored if you have middleware refreshing
                        // user sessions.
                    }
                },
            },
        }
    );
};

// 이 함수는 admin 을 true 로 줘서 하는거 정리하려고.
export const createServerSupabaseAdminClient = async (
    cookieStore?: Awaited<ReturnType<typeof cookies>>
) => {
    return createServerSupabaseClient(cookieStore, true);
};

// 인증 여부 확인 함수
export const requireAuth = async () => {
    const supabase = await createServerSupabaseClient();

    const {
        data: { session },
    } = await supabase.auth.getSession();

    if (!session) {
        // 인증되지 않은 경우 /auth로 리디렉션
        redirect("/auth");
    }

    return session; // 인증된 경우 세션 반환
};

 

 

app/middleware.ts

  • 목적: Next.js 애플리케이션에서 요청 및 응답을 처리하고 Supabase 클라이언트를 적용하기 위한 미들웨어

  • 주요 기능:

    • applyMiddlewareSupabaseClient(): 요청을 처리하며 Supabase 클라이언트를 생성하고, 쿠키를 관리합니다. 요청과 응답에 Supabase 클라이언트를 통합하고 인증 토큰을 갱신합니다.

    • middleware(): applyMiddlewareSupabaseClient()를 호출하여 미들웨어를 구현합니다. 특정 요청 경로에 대해 미들웨어가 동작하도록 설정합니다.

import { createServerClient, type CookieOptions } from "@supabase/ssr";
import { type NextRequest, NextResponse } from "next/server";

export const applyMiddlewareSupabaseClient = async (request: NextRequest) => {
    // Create an unmodified response
    let response = NextResponse.next({
        request: {
            headers: request.headers,
        },
    });

    const supabase = createServerClient(
        process.env.NEXT_PUBLIC_SUPABASE_URL!,
        process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
        {
            cookies: {
                get(name: string) {
                    return request.cookies.get(name)?.value;
                },
                set(name: string, value: string, options: CookieOptions) {
                    // If the cookie is updated, update the cookies for the request and response
                    request.cookies.set({
                        name,
                        value,
                        ...options,
                    });
                    response = NextResponse.next({
                        request: {
                            headers: request.headers,
                        },
                    });
                    response.cookies.set({
                        name,
                        value,
                        ...options,
                    });
                },
                remove(name: string, options: CookieOptions) {
                    // If the cookie is removed, update the cookies for the request and response
                    request.cookies.set({
                        name,
                        value: "",
                        ...options,
                    });
                    response = NextResponse.next({
                        request: {
                            headers: request.headers,
                        },
                    });
                    response.cookies.set({
                        name,
                        value: "",
                        ...options,
                    });
                },
            },
        }
    );

    // refreshing the auth token
    await supabase.auth.getUser();

    return response;
};

export async function middleware(request: NextRequest) {
    return await applyMiddlewareSupabaseClient(request);
}

export const config = {
    matcher: [
        /*
         * Match all request paths except for the ones starting with:
         * - _next/static (static files)
         * - _next/image (image optimization files)
         * - favicon.ico (favicon file)
         * Feel free to modify this pattern to include more paths.
         */
        "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
    ],
};

 

 

이렇게 기본적인 설정들을 해주고

 

기본적인 사이트 설정들을 해주었습니다

 

1) SEO 설정

app/page.tsx

 

public 폴더에 images 라는 폴더를 만들고, JM_logo.png 라는 파일을 추가해두었습니다.

그리고 아래의 코드를 page.tsx 코드 위에다가 붙여넣었습니다 (대체하라는게 아님. 추가하는거임)

export async function generateMetadata() {
    return {
        title: "큐라시의 블로그 입니다",
        description:
            "Next.js와 Supabase를 사용하여 만든 큐라시의 블로그입니다. 최신 기술 스택을 활용하여 빠르고 효율적인 웹 애플리케이션을 제공합니다.",
        openGraph: {
            title: "큐라시의 블로그 입니다",
            description:
                "Next.js와 Supabase를 사용하여 만든 큐라시의 블로그입니다. 최신 기술 스택을 활용하여 빠르고 효율적인 웹 애플리케이션을 제공합니다.",
            images: "/images/JM_logo.png",
        },
    };
}

 

 

2) favicon 변경 (크롬 브라우저의 탭에 들어갈 아이콘)

public 폴더에 favicon.ico 파일을 추가했고, 

app 폴더의 favicon.ico 파일을 삭제했습니다. 저는 사진이나 이런 모든 파일들을 public 에다가 헷갈리지 않게 전부 넣으려고 한 조치입니다!

마지막 수정: 2025. 8. 20.