Blog/backend/Supabase RLS — Məlumatlarını Bank Səviyyəsində Qoru
backend

Supabase RLS — Məlumatlarını Bank Səviyyəsində Qoru

B
Baku Stack AI
·11 aprel 2026·5 dəq oxuma·16 baxış
backend.ascii
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓ ■ ■ ■ SECURITY ▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓ ● Supabase RLS ▓
▓ ─────────────────── → ▓
▓ auth.uid() = user_id ▓
▓ ▓
▓ SELECT ░░ → ✓ own row ▓
▓ SELECT ░░ → ✗ others ▓
▓ ▓
▓ Policy: ▓▓▓▓▓▓▓░░ 80% ▓
▓ Safety: ▓▓▓▓▓▓▓▓▓ 99% ▓
▓ ✓ Bank-level security ▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓

Supabase Row Level Security ilə hər istifadəçi yalnız öz datasını görür. Bank tətbiqi nümunəsi ilə RLS-i addım-addım öyrən.

Supabase RLS — Məlumatlarını Bank Səviyyəsində Qoru

Təsəvvür et: Bakıda bir fintech startup qurmusan. İstifadəçilər AZN balanslarını görə bilir, köçürmə edə bilir. Bir gün səhər "Kapital Bank"-ın müştərisi sənə yazır: "Qardaş, mən başqasının balansını görə bilirəm." Bütün dünya başına yıxılır.

Bu, fantaziya deyil. 2023-cü ildə dünyada data breach-lərin 82%-i yanlış konfiqurasiya edilmiş API və ya authorization boşluqlarından qaynaqlanıb (Verizon DBIR 2023). Supabase istifadə edirsənsə, sənin bu boşluğu bağlayan silahın Row Level Security (RLS)-dir.

Bu gün bunu real bank tətbiqi nümunəsi ilə ətraflı öyrənəcəyik.


RLS Nədir və Niyə Vacibdir?

Row Level Security — PostgreSQL-in daxili mexanizmidir. Hər cədvələ "siyasət" (policy) yazırsan və verilənlər bazası səviyyəsində müəyyən edirsən: kim hansı sətirləri görə bilər, dəyişə bilər, silə bilər.

Supabase bunu çox rahat şəkildə inteqrasiya edib. Amma default olaraq RLS söndürülmüş olur. Yəni cədvəl yaradıb RLS-i aktiv etməsən, anon key ilə bütün məlumatları çəkmək olur. Bəli, hətta Postman-dan belə.

Bunu Bakıdakı reallıqla izah edim: Tutaq ki, sən 28 Mal-da oturan bir startup-da işləyirsən, aylıq 1800 AZN alırsan, Supabase-də layihə qurmusan. Frontend-dən supabase.from('accounts').select('*') yazırsan — əgər RLS yoxdursa, hər kəs hər kəsin datasını çəkə bilər. Bura kart nömrəsi, balans, telefon — hər şey daxildir.


Addım 1: Cədvəlləri Yaradaq

Bank tətbiqimiz üçün iki əsas cədvəl lazımdır:

sql
-- İstifadəçi hesabları CREATE TABLE accounts ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, user_id UUID REFERENCES auth.users(id) NOT NULL, full_name TEXT NOT NULL, balance NUMERIC(12, 2) DEFAULT 0.00, currency TEXT DEFAULT 'AZN', created_at TIMESTAMPTZ DEFAULT now() ); -- Köçürmə tarixçəsi CREATE TABLE transactions ( id UUID DEFAULT gen_random_uuid() PRIMARY KEY, sender_id UUID REFERENCES accounts(id) NOT NULL, receiver_id UUID REFERENCES accounts(id) NOT NULL, amount NUMERIC(12, 2) NOT NULL, note TEXT, created_at TIMESTAMPTZ DEFAULT now() );

Burada user_id Supabase Auth-dan gələn istifadəçi ID-sidir. RLS-in bütün məntiqi bunun üzərində qurulacaq.


Addım 2: RLS-i Aktiv Et

sql
-- RLS-i hər iki cədvəl üçün yandırırıq ALTER TABLE accounts ENABLE ROW LEVEL SECURITY; ALTER TABLE transactions ENABLE ROW LEVEL SECURITY;

Vacib: RLS aktiv olan kimi, heç bir policy yazılmayıbsa, heç kim heç nə görə bilmir — hətta authenticated istifadəçilər belə. Bu, "default deny" prinsipidir və məhz bu, onu güclü edir.


Addım 3: Siyasətləri (Policy) Yazaq

İndi əsas hissə. Hər istifadəçi yalnız öz hesabını görsün:

sql
-- İstifadəçi yalnız öz hesab məlumatını oxuya bilsin CREATE POLICY "Users can view own account" ON accounts FOR SELECT USING (auth.uid() = user_id); -- İstifadəçi yalnız öz balansını yeniləyə bilsin CREATE POLICY "Users can update own account" ON accounts FOR UPDATE USING (auth.uid() = user_id) WITH CHECK (auth.uid() = user_id);

auth.uid() — Supabase-in möcüzəsi. JWT token-dən avtomatik istifadəçi ID-sini çıxarır. Heç bir middleware, heç bir əlavə kod lazım deyil.

Transaksiyalar üçün isə bir az daha maraqlıdır — istifadəçi həm göndərən, həm qəbul edən ola bilər:

sql
-- İstifadəçi öz göndərdiyi və ya aldığı köçürmələri görsün CREATE POLICY "Users can view own transactions" ON transactions FOR SELECT USING ( sender_id IN ( SELECT id FROM accounts WHERE user_id = auth.uid() ) OR receiver_id IN ( SELECT id FROM accounts WHERE user_id = auth.uid() ) ); -- Yalnız öz hesabından köçürmə edə bilsin CREATE POLICY "Users can insert own transactions" ON transactions FOR INSERT WITH CHECK ( sender_id IN ( SELECT id FROM accounts WHERE user_id = auth.uid() ) );

Bu policy ilə bir istifadəçi başqasının adından köçürmə edə bilməz. sender_id mütləq onun öz hesabına aid olmalıdır.


Addım 4: Frontend-dən Test Et

İndi JavaScript tərəfdən yoxlayaq:

javascript
import { createClient } from '@supabase/supabase-js'; const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY); // Login olmuş istifadəçi öz balansını görür const { data, error } = await supabase .from('accounts') .select('full_name, balance, currency'); console.log(data); // Nəticə: [{ full_name: "Orxan Məmmədov", balance: 2450.00, currency: "AZN" }] // Yalnız öz datası gəlir — başqalarının balansı GÖRÜNMÜR

Burada WHERE yazmağa ehtiyac yoxdur. RLS avtomatik filtrləyir. Bu, developer üçün həm rahatdır, həm də təhlükəsizdir — çünki WHERE yazmağı unuda bilərsən, amma RLS heç vaxt unutmur.


Tez-tez Edilən Səhvlər

  • RLS-i aktiv edib policy yazmamaq → Heç kim heç nə görə bilmir, frontend boş array qaytarır. Supabase dashboard-da "No rows returned" görürsənsə, ilk bura bax.
  • Service role key-i frontend-ə qoymaq → Bu key RLS-i bypass edir. Onu YALNIZ server-side (Edge Functions, backend) istifadə et. .env-ə yaz, heç vaxt client bundle-a düşməsin.
  • USINGWITH CHECK fərqini bilməməkUSING oxuma və mövcud sətirləri yoxlayır. WITH CHECK yeni/dəyişdirilən sətirin doğruluğunu yoxlayır. INSERT və UPDATE üçün hər ikisi lazımdır.
  • Subquery-lərdə performans problemi → Çox böyük cədvəllərdə (100K+ sətir) subquery əvəzinə JOIN və ya materialized view istifadə et. Index əlavə etməyi unutma: CREATE INDEX idx_accounts_user_id ON accounts(user_id);

Admin Panel Üçün Ayrı Policy

Çox vaxt admin paneldə bütün istifadəçilərin datasını görmək lazım olur. Bunun üçün custom claim və ya ayrı rol istifadə edə bilərsən:

sql
CREATE POLICY "Admins can view all accounts" ON accounts FOR SELECT USING ( auth.jwt() ->> 'role' = 'admin' );

Supabase-də custom claim əlavə etmək üçün auth.users cədvəlindəki raw_app_meta_data sahəsinə {"role": "admin"} yazmalısan. Bunu Dashboard-dan və ya Edge Function-dan etmək olar.


Nəticə: RLS Sənin Gecə Yuxundur

Supabase RLS ilə sən verilənlər bazası səviyyəsində qoruma qurursan. Frontend-dəki bug, unudulmuş WHERE, yanlış API endpoint — bunların heç biri data leak-ə səbəb ola bilməz, çünki PostgreSQL özü qapını bağlayıb.

Bakıda fintech, e-commerce və ya hər hansı SaaS layihə qurursan? RLS-siz production-a çıxma. Bu, kilidlənməmiş bank qapısı kimidir — içəridə heç kim olmaya bilər, amma risk həmişə var.

Azərbaycan bazarında Supabase ilə işləyən layihələr artır. Birbank, m10 kimi tətbiqlərin infrastrukturu fərqli olsa da, prinsip eynidir: hər istifadəçi yalnız öz datasını görməlidir. RLS bunu bir neçə sətir SQL ilə həll edir.

Bunu öyrən, portfoliona əlavə et, müsahibədə danış. 1800 AZN-dən 3500 AZN-ə keçidin yolu belə detallardadır. 🚀

Oxşar məqalələr

backend.ascii
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓ ■ ■ ■ BACKEND ▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓ → GET /api/products ▓
▓ ● Redis: 0.3ms ✓ ▓
▓ ● PgSQL: 18ms ↓ ▓
▓ ▓
▓ Cache HIT ratio: ▓
▓ ▓▓▓▓▓▓▓▓▓░░ 92% ▓
▓ ▓
▓ Trafik piki: ▓
▓ ░░▒▒▓▓▓▓▓▓▓▓ Novruz ▓
▓ Response: 180ms ⚡ ▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓

Redis ilə Caching — Azərbaycan Trafik Piklərini İdarə Etmək

Bayram günləri saytın çökür? Redis ilə caching qurub, saniyədə 100K sorğunu rahat idarə etməyi öyrən — real kod və rəqəmlərlə.

backend.ascii
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓ ■ ■ ■ DATABASE ▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓ 🐘 PostgreSQL ▓
▓ ▓▓▓▓▓▓▓▓▓▓░░░░ 71% ▓
▓ → SQL ● ACID ● JOIN ▓
▓ → Bakı corp: ✓✓✓ ▓
▓──────────────────────▓
▓ 🍃 MongoDB ▓
▓ ▓▓▓▓▓▓▓▓░░░░░░ 55% ▓
▓ → NoSQL ● Fast ● MVP ▓
▓ → Startap: ✓✓✓ ▓
▓ Seçim → Layihəyə bax ▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓

PostgreSQL vs MongoDB — Bakı Startapın üçün Hansını Seçməlisən?

Azərbaycanlı developer olaraq startap qurmaq istəyirsən? PostgreSQL və MongoDB arasında düzgün seçim etmək üçün real kod, rəqəmlər və yerli kontekst burada.

backend.ascii
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓ ■ ■ ■ FINTECH API ▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓ User → [myapp.az] ▓
▓ ↓ POST /create ▓
▓ Backend → Epoint API ▓
▓ ↓ redirect_url ▓
▓ User → ödəniş səhifə ▓
▓ ↓ kart: 4169 7xxx ▓
▓ Epoint → webhook ▓
▓ ↓ signature ✓ ▓
▓ DB: status=paid ● ▓
▓ ▓▓▓▓▓▓▓▓░░ 80% done ▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓

Epoint və PAYRIFF: Azərbaycan Fintech Ödəniş API İnteqrasiyası

Azərbaycanda ödəniş qəbul etmək istəyirsən? Epoint və PAYRIFF API-lərini real kod nümunələri ilə addım-addım inteqrasiya edək — sandbox-dan production-a qədər.

← Bloqa qayıt