Drizzle를 사용하면 모든 Postgres 테이블에 Row-Level Security (RLS)를 활성화하고, 다양한 옵션으로 정책을 생성하며, 해당 정책이 적용되는 역할을 정의하고 관리할 수 있습니다.
Drizzle는 원하는 방식으로 사용할 수 있는 Postgres 정책 및 역할의 원시 표현을 지원합니다. 이는 Neon 및 Supabase와 같은 인기 있는 Postgres 데이터베이스 제공자와 함께 작동합니다.
Drizzle에는 두 데이터베이스 제공자를 위한 특정 사전 정의된 RLS 역할 및 함수가 있지만, 자체 로직을 정의할 수도 있습니다.
Enable RLS
IMPORTANT
How it works in 0.x versions
정책을 추가하지 않고 테이블에서 RLS만 활성화하려면 .enableRLS()를 사용할 수 있습니다.
PostgreSQL 문서에 언급된 대로:
If no policy exists for the table, a default-deny policy is used, meaning that no rows are visible or can be modified.
Operations that apply to the whole table, such as TRUNCATE and REFERENCES, are not subject to row security.
v1.0.0-beta.1부터 .enableRLS()는 지원 중단되었으며,
정책을 추가하지 않고 테이블에서 RLS만 활성화하려면 pgTable.withRLS(...)를 사용할 수 있습니다.
PostgreSQL 문서에 언급된 대로:
If no policy exists for the table, a default-deny policy is used, meaning that no rows are visible or can be modified.
Operations that apply to the whole table, such as TRUNCATE and REFERENCES, are not subject to row security.
정책이 적용되는 역할을 지정합니다. 가능한 값으로는 public, current_role, current_user, session_user 또는 문자열로 된 다른 역할 이름이 있습니다. pgRole 객체를 참조할 수도 있습니다.
for
이 정책이 적용될 명령을 정의합니다. 가능한 값은 all, select, insert, update, delete입니다.
using
정책 생성 문의 USING 부분에 적용될 SQL 문입니다.
withCheck
정책 생성 문의 WITH CHECK 부분에 적용될 SQL 문입니다.
기존 테이블에 정책 연결
데이터베이스의 기존 테이블에 정책을 연결해야 하는 상황이 있습니다.
가장 일반적인 사용 사례는 Neon 또는 Supabase와 같은 데이터베이스 제공자를 사용할 때
기존 테이블에 정책을 추가해야 하는 경우입니다. 이 경우 .link() API를 사용할 수 있습니다.
import { sql } from "drizzle-orm";import { pgPolicy } from "drizzle-orm/pg-core";import { authenticatedRole, realtimeMessages } from "drizzle-orm/supabase";export const policy = pgPolicy("authenticated role insert policy", { for: "insert", to: authenticatedRole, using: sql``,}).link(realtimeMessages);
Migrations
drizzle-kit을 사용하여 스키마와 역할을 관리하는 경우, Drizzle 스키마에 정의되지 않은 역할을 참조하고 싶을 수 있습니다. 이러한 경우 drizzle 스키마에서 각 역할을 정의하고 .existing()으로 표시하지 않고도 drizzle-kit이 이러한 역할 관리를 건너뛰도록 할 수 있습니다.
이러한 경우 drizzle.config.ts에서 entities.roles를 사용할 수 있습니다. 전체 참조는 drizzle.config.ts 문서를 참조하세요.
기본적으로 drizzle-kit은 역할을 관리하지 않으므로, drizzle.config.ts에서 이 기능을 활성화해야 합니다.
이를 통해 코드에서 사용할 수 있으며, Drizzle Kit은 이를 기존 데이터베이스로 취급하여
다른 엔티티에 연결하기 위한 정보로만 사용합니다.
import { foreignKey, pgPolicy, pgTable, text, uuid } from "drizzle-orm/pg-core";import { sql } from "drizzle-orm/sql";import { authenticatedRole, authUsers } from "drizzle-orm/supabase";export const profiles = pgTable( "profiles", { id: uuid().primaryKey().notNull(), email: text().notNull(), }, (table) => [ foreignKey({ columns: [table.id], // Supabase의 auth 테이블 참조 foreignColumns: [authUsers.id], name: "profiles_id_fk", }).onDelete("cascade"), pgPolicy("authenticated can view all profiles", { for: "select", // Supabase의 사전 정의된 역할 사용 to: authenticatedRole, using: sql`true`, }), ]);
Supabase에 존재하는 테이블에 정책을 추가하는 예제를 확인해 보겠습니다.
import { sql } from "drizzle-orm";import { pgPolicy } from "drizzle-orm/pg-core";import { authenticatedRole, realtimeMessages } from "drizzle-orm/supabase";export const policy = pgPolicy("authenticated role insert policy", { for: "insert", to: authenticatedRole, using: sql``,}).link(realtimeMessages);
Drizzle RLS를 Supabase와 함께 사용하는 방법과 실제 쿼리를 수행하는 방법을 보여주는 훌륭한 예제도 있습니다.
또한 Supabase에 대한 모든 트랜잭션 작업을 처리할 수 있는 훌륭한 래퍼인 createDrizzle도 포함되어 있습니다.
향후 릴리스에서는 drizzle-orm/supabase로 이동되어 기본적으로 사용할 수 있게 될 것입니다.
// https://github.com/orgs/supabase/discussions/23224// Should be secure because we use the access token that is signed, and not the data read directly from the storageexport async function createDrizzleSupabaseClient() { const { data: { session }, } = await createClient().auth.getSession(); return createDrizzle(decode(session?.access_token ?? ""), { admin, client });}async function getRooms() { const db = await createDrizzleSupabaseClient(); return db.rls((tx) => tx.select().from(rooms));}