Supabase는 PostgreSQL 데이터베이스, 인증, 저장소 및 실시간 API를 제공하는 오픈 소스 백엔드 서비스(BaaS)입니다.
Supabase 는 PostgreSQL 데이터베이스 , 인증 , 저장소 , 실시간 API를 제공하는 오픈 소스 백엔드 서비스(BaaS)로, RESTful 또는 GraphQL 인터페이스를 통해 바로 사용할 수 있습니다. 인프라를 관리하지 않고도 확장 가능한 웹 및 모바일 애플리케이션을 구축할 수 있도록 설계되었습니다.
- Backend as a Service; 서비스형 백엔드
1. 서버와 클라이언트 컨텍스트 분리
일반적인 실수는 Supabase 키를 오용하여 클라이언트 측에서 중요한 액세스 권한을 노출하는 것입니다.
Supabase는 anon(공개) 키와 service_role(비공개) 키의 두 가지 유형을 제공합니다 .
키는 항상 service_role서버 측에 보관하세요.
클라이언트 연결(브라우저 보안):
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
서버 연결(관리자 권한):
import { createClient } from '@supabase/supabase-js';
const supabaseAdmin = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
);
프런트엔드에서 비밀 키를 사용하면 service_role 행 수준 보안이 우회되므로 사용하지 마세요.
또한, 보안이 침해되면 전체 데이터베이스가 손상될 수 있습니다.
2. 유형 안전을 위해 Drizzle ORM과 통합
Drizzle ORM은 강력하고 형식에 안전한 TypeScript용 SQL 쿼리 생성기입니다.
Supabase를 사용하는 경우, 연결된 문자열을 통해 Drizzle을 PostgreSQL 인스턴스에 직접 연결할 수 있습니다.
설정 예시:
import postgres from 'postgres';
import { drizzle } from 'drizzle-orm/postgres-js';
const client = postgres(process.env.SUPABASE_DB_URL); // 예:'postgres://user:password@host:5432/db'
export const db = drizzle(client);
스키마를 명시적으로 정의
import { pgTable, serial, varchar, timestamp } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
email: varchar('email', { length: 255 }).notNull(),
createdAt: timestamp('created_at').defaultNow()
});
Drizzle은 스키마, 마이그레이션 및 쿼리를 완벽하게 제어하는 동시에 런타임 오버헤드 없이 정적 형식의 안전성을 제공합니다.
3. Supabase 정책을 사용하여 행 수준 보안 적용
Supabase는 PostgreSQL의 기본 행 수준 보안(RLS)을 활용하여 데이터에 대한 행 수준 액세스를 제한합니다.
RLS를 활성화하고 구성하는 것은 안전한 다중 사용자 애플리케이션을 구축하는 데 중요합니다.
RLS 활성화:
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
정책 생성
CREATE POLICY "Users can access their profile"
ON profiles
FOR SELECT USING (auth.uid() = id);
이러한 전략은 auth.uid()현재 인증된 사용자의 ID를 반환하는 함수에 의존합니다.
올바르게 구성하면 사용자 간에 데이터가 유출되지 않고 프런트엔드에서 Supabase 클라이언트를 안전하게 사용할 수 있습니다.
4. 보안 비즈니스 로직 및 백그라운드 작업을 위해 에지 함수 사용
Supabase 에지 함수를 사용하면 Deno를 사용하여 서버 측 코드를 안전하게 실행할 수 있습니다.
이 기능은 이메일 전송, 웹훅 서명 확인, Supabase Realtime 또는 데이터베이스 변경으로 인해 발생하는 이벤트 처리에 유용합니다.
예: 트랜잭션 이메일 전송하기
// sendWelcomeEmail.ts
import { serve } from "https://deno.land/std/http/server.ts";
serve(async (req) => {
const { email } = await req.json();
return new Response(JSON.stringify({ status: "sent" }), { status: 200 });
});
배포 명령:
supabase functions deploy sendWelcomeEmail
Edge 기능은 사용자와 가깝게 실행되고 Supabase 인증 및 저장소와 통합되며 키 및 액세스 제어에 대한 기본 지원 기능을 제공합니다.
5. Supabase Storage: 서명된 URL 및 액세스 제어
Supabase 스토리지는 S3 호환 개체 스토리지를 기반으로 구축되었습니다. RLS와 서명된 URL을 사용하여 파일을 저장하고 액세스를 제어할 수 있습니다.
파일 업로드:
const { data, error } = await supabase.storage
.from('avatars')
.upload('user123/avatar.png', file);
서명된 URL을 생성(예: 비공개 다운로드의 경우):
const { data } = await supabase.storage
.from('avatars')
.createSignedUrl('user123/avatar.png', 60); // 60초 동안 유효
파일에 대한 액세스는 데이터베이스 행과 마찬가지로 정책에 의해 제어됩니다.
예를 들어, RLS를 사용하여 다운로드를 파일 소유자로 제한할 수 있습니다.
6. Drizzle ORM을 Supabase Auth User와 연결
Supabase Auth를 사용하면 사용자 ID가 UUID로 저장됩니다. Drizzle을 사용하여 자신의 애플리케이션 테이블과 연결하려면 외래 키를 올바르게 선언하세요.
import { uuid } from 'drizzle-orm/pg-core';
export const profiles = pgTable('profiles', {
id: uuid('id').primaryKey(), // Supabase Auth UID
fullName: varchar('full_name', { length: 100 }),
});
이렇게 하면 사용자 테이블이 인증 시스템과 일치하고 적절한 참조 무결성이 적용됩니다.