Bảo mật phải ở DB, không chỉ ở code
Sai lầm chết người của người mới: chỉ kiểm tra quyền trong code frontend. Nhưng bất kỳ ai cũng có thể gọi thẳng API/DB. Row Level Security (RLS) đặt luật bảo mật ngay tại database: dù request đến từ đâu, Postgres tự quyết định dòng nào người dùng được thấy/sửa.
RLS hoạt động thế nào?
Bật RLS cho một bảng → mặc định chặn tất cả. Sau đó bạn viết các policy mở quyền có điều kiện.
-- 1. Bật RLS
alter table public.posts enable row level security;
-- 2. Ai cũng đọc được post công khai
create policy "Public posts are viewable by everyone"
on public.posts for select
using ( is_public = true );
-- 3. Chỉ chủ bài mới sửa được bài của mình
create policy "Users can update own posts"
on public.posts for update
using ( auth.uid() = user_id );
auth.uid() là hàm Supabase trả về ID người dùng đang đăng nhập — trái tim của RLS.
Các pattern policy thường gặp
| Nhu cầu | Điều kiện (using/with check) |
|---|---|
| Ai cũng đọc dữ liệu công khai | is_public = true |
| Chỉ chủ sở hữu đọc/sửa/xoá | auth.uid() = user_id |
| Chỉ thành viên cộng đồng | exists (select 1 from members where ...) |
| Chỉ admin | auth.jwt() ->> 'role' = 'admin' |
💡 Nhờ AI viết policy: "Viết RLS policy cho bảng
courses: ai cũng đọc course của community công khai, chỉ owner của community mới được thêm/sửa/xoá course." Luôn đọc kỹ policy AI viết — đây là lớp bảo mật, sai một điều kiện là lộ dữ liệu.
Triggers: tự động hoá tại database
Trigger là hàm tự chạy khi có sự kiện (insert/update/delete). Dùng cho các việc nên xảy ra bất kể code gọi từ đâu:
-- Tự cập nhật cột updated_at mỗi lần sửa
create or replace function update_updated_at()
returns trigger as $$
begin
new.updated_at = now();
return new;
end;
$$ language plpgsql;
create trigger trg_posts_updated
before update on public.posts
for each row execute function update_updated_at();
Use case kinh điển: tự tạo profile khi có user mới đăng ký (trigger trên auth.users insert vào public.profiles).
Quy tắc an toàn
- Bật RLS cho MỌI bảng chứa dữ liệu người dùng. Quên bật = dữ liệu phơi bày.
- Test policy bằng tài khoản thật (đăng nhập user A, thử đọc dữ liệu user B — phải bị chặn).
- Service role bỏ qua RLS — chỉ dùng service key ở server, tuyệt đối không để lộ ra client.
- Trigger viết bằng AI vẫn phải review — nó chạy tự động nên lỗi lan rộng.
Bài tập
Bật RLS cho một bảng, viết 2 policy (đọc công khai + sửa bởi chủ sở hữu), rồi test bằng 2 tài khoản khác nhau để xác nhận cách ly dữ liệu.
