Should I use Postgres Row-Level Security or application-level workspace checks?
It depends on how your application connects to Postgres. If browser or mobile clients query the database directly through PostgREST, Row-Level Security (RLS) is mandatory. If all traffic flows through a server-side TypeScript boundary, explicit membership checks on every query are your primary defense, and RLS serves as defense-in-depth against forgotten WHERE clauses. Combine live session-to-membership resolution with indexed workspace_id policies. supastack enforces server-side workspace guards across web, mobile, and desktop, and provides a free RLS policy generator for Supabase tables.
Uygulama korumaları ve veritabanı politikaları farklı arızaları çözer
Geliştiriciler genellikle uygulama düzeyinde yetkilendirme ile Postgres Row-Level Security'yi (RLS) birbirini dışlayan seçenekler olarak görür. Pratikte farklı hataları yakalarlar: sunucu tarafı korumalar iş mantığı çalışmadan önce rol hiyerarşisini, erişim hakkı kontrollerini ve denetim kayıtlarını uygularken, RLS unutulan bir WHERE workspace_id = ... koşulunun tüm kiracıların satırlarını sızdırmasını engeller.
İster Supabase ister Drizzle ile kendi barındırdığınız Postgres'i kullanın, kiracıya ait her tablo boş olmayan bir workspace_id yabancı anahtarı taşımalıdır. Çalışma alanı sınırları yazısı, bu kapsamın neden her zaman sunucuda türetilmesi gerektiğini açıklar.
- Uygulama korumaları oturum güncelliğini, üye rollerini (
owner,admin,member) ve özellik haklarını doğrular. - Veritabanı RLS politikaları, doğrudan istemci sorguları veya ham SQL yardımcıları kullanıldığında sert bir güvenlik tabanı oluşturur.
- Her iki katman da tek bir doğruluk kaynağına dayanır:
workspace_membersbirleştirme tablosu.
Eski çerezlere güvenmek yerine canlı üyeliği çözümleyin
Bir tarayıcı çerezinde veya istemci başlığında currentWorkspaceId saklamak gezinme için kullanışlıdır, ancak çerez bir yetki değil yalnızca bir tercihtir. Bir yönetici ekip arkadaşını çalışma alanından çıkarırsa, o kullanıcının tarayıcısı eski çalışma alanı çerezini tutmaya devam eder.
Her istekte etkin oturumu workspace_members tablosuyla birleştirin. Üyelik satırı silindiğinde, bir JWT'nin veya oturum çerezinin süresinin dolmasını beklemek yerine isteği derhal reddedin. Giriş formunun ötesinde kimlik doğrulama yazısı, kimliğin bu kontrole nasıl aktığını adım adım izler.
export async function requireWorkspaceViewer(requestedWorkspaceId?: string) {
const session = await requireAuthenticatedSession();
const membership = await db.query.workspaceMembers.findFirst({
where: and(
eq(workspaceMembers.userId, session.user.id),
requestedWorkspaceId
? eq(workspaceMembers.workspaceId, requestedWorkspaceId)
: undefined,
),
with: { workspace: true },
});
if (!membership) throw new ForbiddenError("Not a member of this workspace");
return { user: session.user, workspace: membership.workspace, role: membership.role };
}Hızlı ve indekslenmiş Row-Level Security politikaları yazın
Her satırda doğrudan auth.uid() çağıran saf RLS politikaları, Postgres'i fonksiyonu her satır için yeniden hesaplamaya zorlar. (select auth.uid()) ifadesini skaler bir alt sorguya almak, sorgu planlayıcısının değeri bir initPlan olarak önbelleğe almasını sağlar ve (workspace_id, user_id) üzerindeki bileşik bir indeks üyelik aramalarını milisaniyenin altında tutar.
Elle tekrarlayan SQL yazmadan çok kiracılı tablolar için çalıştırmaya hazır SELECT, INSERT, UPDATE ve DELETE politikalarını ücretsiz Supabase RLS Politika Oluşturucu ile üretebilirsiniz.
CREATE INDEX IF NOT EXISTS idx_workspace_members_lookup
ON workspace_members (workspace_id, user_id);
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
CREATE POLICY "workspace_members_manage_documents"
ON documents FOR ALL TO authenticated
USING (
workspace_id IN (
SELECT wm.workspace_id FROM workspace_members wm
WHERE wm.user_id = (SELECT auth.uid())
)
)
WITH CHECK (
workspace_id IN (
SELECT wm.workspace_id FROM workspace_members wm
WHERE wm.user_id = (SELECT auth.uid())
AND wm.role IN ('owner', 'admin', 'member')
)
);RLS ve çalışma alanı kimlik doğrulaması hakkında sık sorulan sorular
Çok kiracılı Postgres kuran ekipler; servis rolleri, arka plan işleri ve performans etrafında aynı uç durumlarla karşılaşır.
- Drizzle ORM veya Prisma RLS'yi atlar mı? — Evet, sunucunuz
postgressüper kullanıcısı veya Supabaseservice_roleanahtarıyla bağlanıyorsa atlar. Bu nedenle sunucu eylemleri ve API rotalarırequireWorkspaceViewer()çağırmalı ve her sorguyuworkspaceIdile sınırlandırmalıdır. - RLS politikalarında
(select auth.uid())neden parantez içine alınır? — Postgres iyileştiricisineauth.uid()değerini taranan her satır yerine sorgu başına bir kez değerlendirmesini söyler ve büyük tablolarda sıralı tarama yavaşlamalarını önler. - Arka plan işleri kiracı verilerine nasıl erişmelidir? — Doğrulanmış
workspaceIddeğerini kimliği doğrulanmış sunucu rotasından iş yüküne aktarın ve çalışan okuma/yazma işlemlerini buworkspaceIdile sınırlandırın. - Kiracı izolasyonunun gerçekten korunduğunu nasıl doğrularım? — Kullanıcı A'nın web, mobil ve API rotaları üzerinden Kullanıcı B'nin kayıt kimliğini istediği veya değiştirmeye çalıştığı otomatik negatif testler yazın ve sıfır satır değişikliğiyle
403/404döndüğünü doğrulayın.