03 thg 3, 2025·8 phút đọc

Mẫu PostgreSQL row-level security cho ứng dụng đa-tenant

Tìm hiểu PostgreSQL row-level security với các mẫu thực tế để cô lập tenant và quy tắc theo vai trò, để truy cập được áp dụng ở cơ sở dữ liệu thay vì chỉ ở ứng dụng.

Mẫu PostgreSQL row-level security cho ứng dụng đa-tenant

Tại sao việc bắt buộc kiểm soát ở cấp cơ sở dữ liệu lại quan trọng trong ứng dụng doanh nghiệp

Các ứng dụng doanh nghiệp thường có quy tắc như “người dùng chỉ được thấy dữ liệu của công ty họ” và “chỉ quản lý mới được duyệt hoàn tiền.” Nhiều đội thực thi những quy tắc đó ở UI hoặc API và cho rằng thế là đủ. Vấn đề là: mỗi đường dẫn thêm tới cơ sở dữ liệu lại là một cơ hội để rò rỉ dữ liệu — công cụ admin nội bộ, job nền, truy vấn phân tích, endpoint bị lãng quên hoặc một lỗi bỏ quên kiểm tra nào đó.

Cô lập tenant nghĩa là một khách hàng (tenant) không bao giờ đọc hay thay đổi dữ liệu của khách hàng khác, ngay cả vô tình. Quyền theo vai trò nghĩa là những người trong cùng tenant vẫn có quyền khác nhau, như agent vs manager vs finance. Những quy tắc này dễ mô tả nhưng khó giữ nhất quán khi chúng sống ở nhiều nơi.

PostgreSQL row-level security (RLS) là một tính năng của cơ sở dữ liệu cho phép chính cơ sở dữ liệu quyết định hàng nào một yêu cầu có thể thấy hoặc thay đổi. Thay vì hy vọng mọi truy vấn trong app nhớ đúng mệnh đề WHERE, cơ sở dữ liệu sẽ tự động áp dụng các chính sách.

RLS không phải là tấm khiên thần kỳ cho mọi thứ. Nó không thiết kế schema của bạn, không thay thế authentication, và không bảo vệ khỏi người đã có quyền mạnh trong DB (ví dụ superuser). Nó cũng không ngăn lỗi logic như “ai đó có thể update một hàng mà họ không thể select” trừ khi bạn viết chính sách cho cả đọc và ghi.

Những gì bạn nhận được là một mạng lưới an toàn mạnh:

  • Một bộ quy tắc cho mọi đường dẫn tới cơ sở dữ liệu
  • Ít “ối giời ơi” hơn khi một tính năng mới được deploy
  • Audit rõ ràng hơn, vì quy tắc truy cập hiển thị trong SQL
  • Phòng thủ tốt hơn nếu một lỗi API lọt qua

Có chi phí thiết lập nhỏ. Bạn cần một cách nhất quán để truyền “đây là ai” và “thuộc tenant nào” vào DB, và cần duy trì các chính sách khi app phát triển. Lợi ích rất lớn, nhất là với SaaS và công cụ nội bộ nơi dữ liệu khách hàng nhạy cảm được lưu trữ.

Kiến thức cơ bản về Row-Level Security không rườm rà thuật ngữ

Row-Level Security (RLS) tự động lọc hàng mà một truy vấn có thể thấy hoặc thay đổi. Thay vì dựa vào từng màn hình, endpoint API hay báo cáo để “nhớ” quy tắc, cơ sở dữ liệu sẽ áp dụng chúng cho bạn.

Với PostgreSQL row-level security, bạn viết các chính sách được kiểm tra trên mỗi SELECT, INSERT, UPDATE, và DELETE. Nếu chính sách nói “người này chỉ thấy hàng của tenant A,” thì một trang admin bị quên, một truy vấn mới, hay một hotfix vội vẫn có cùng rào chắn.

RLS khác với GRANT/REVOKE. GRANT quyết định một role có được chạm vào một bảng hay không (hoặc cột cụ thể). RLS quyết định hàng nào bên trong bảng đó được phép. Thực tế, bạn thường dùng cả hai: GRANT để giới hạn ai có thể truy cập bảng, và RLS để giới hạn cái họ có thể truy cập bên trong đó.

Nó cũng chịu được trong thế giới lộn xộn ngoài đời. Views thường tuân theo RLS vì truy cập bảng nền vẫn kích hoạt chính sách. Joins và subqueries vẫn bị lọc, nên người dùng không thể “join để chui” vào dữ liệu của người khác. Và chính sách áp dụng bất kể client nào chạy truy vấn: code app, console SQL, job nền hay công cụ báo cáo.

RLS phù hợp khi bạn cần cô lập tenant chặt, có nhiều cách truy vấn cùng dữ liệu, hoặc nhiều vai trò chia sẻ bảng (thường thấy trong SaaS và công cụ nội bộ). Nó có thể quá thừa cho app nhỏ chỉ có một backend đáng tin cậy, hoặc dữ liệu không nhạy cảm và không bao giờ rời một service kiểm soát. Khi bạn có hơn một entry point (admin tool, export, BI, script), RLS hầu như luôn có lợi.

Bắt đầu bằng việc vẽ sơ đồ tenants, vai trò và quyền sở hữu dữ liệu

Trước khi viết một chính sách, hãy làm rõ ai sở hữu gì. PostgreSQL RLS hoạt động tốt nhất khi mô hình dữ liệu của bạn đã phản ánh tenants, vai trò và quyền sở hữu.

Bắt đầu với tenants. Trong hầu hết app SaaS, quy tắc đơn giản nhất là: mọi bảng chia sẻ chứa dữ liệu khách hàng đều có tenant_id. Điều này bao gồm các bảng “rõ ràng” như invoices, nhưng cũng cả những thứ hay quên như attachments, comments, audit logs, và job nền.

Tiếp theo, đặt tên các vai trò mà người thật sự dùng. Giữ tập nhỏ và dễ hiểu: owner, manager, agent, read-only. Đó là các vai trò nghiệp vụ mà bạn sẽ ánh xạ vào kiểm tra trong chính sách (không giống hẳn các database role).

Rồi quyết định record thuộc về ai. Một số bảng thuộc sở hữu một user (ví dụ private note). Bảng khác thuộc sở hữu team (ví dụ shared inbox). Trộn cả hai mà không có kế hoạch sẽ dẫn đến chính sách khó đọc và dễ bị qua mặt.

Cách đơn giản để ghi lại quy tắc là trả lời cùng bộ câu hỏi cho mỗi bảng:

  • Ranh giới tenant là gì (cột nào thực thi nó)?
  • Ai có thể đọc hàng (theo vai trò và theo quyền sở hữu)?
  • Ai có thể tạo và cập nhật hàng (và trong điều kiện nào)?
  • Ai có thể xóa hàng (thường nghiêm ngặt nhất)?
  • Ngoại lệ nào được phép (nhân viên hỗ trợ, tự động hóa, export)?

Ví dụ: “Invoices” có thể cho phép managers xem tất cả hóa đơn tenant, agents xem hóa đơn cho khách hàng được gán, và read-only chỉ được xem nhưng không sửa. Quyết định trước những quy tắc nào phải nghiêm ngặt (cô lập tenant, xóa) và cái nào linh hoạt (tầm nhìn rộng cho managers). Nếu bạn dựng bằng công cụ no-code như AppMaster, việc mapping này cũng giúp giữ kỳ vọng UI và quy tắc DB khớp nhau.

Các mẫu thiết kế cho bảng đa-tenant

RLS đa-tenant hoạt động tốt nhất khi bảng của bạn có hình dạng nhất quán. Nếu mỗi bảng lưu tenant theo cách khác nhau, chính sách của bạn sẽ thành một câu đố. Một khuôn dạng nhất quán giúp RLS dễ đọc, dễ test và dễ duy trì.

Bắt đầu bằng việc chọn một định danh tenant duy nhất và dùng nó khắp nơi. UUID phổ biến vì khó đoán và dễ sinh ở nhiều hệ. Số nguyên cũng ổn, nhất là cho app nội bộ. Slug (như "acme") thân thiện với người dùng nhưng có thể thay đổi, nên coi đó là trường hiển thị, không phải khóa chính.

Với dữ liệu theo tenant, thêm cột tenant_id vào mọi bảng thuộc về tenant, và đặt NOT NULL khi có thể. Nếu một hàng có thể tồn tại không có tenant, đó thường là dấu hiệu xấu — nghĩa là bạn đang trộn dữ liệu global và tenant trong cùng một bảng, khiến chính sách RLS khó và mong manh.

Index là đơn giản nhưng quan trọng. Hầu hết truy vấn trong app SaaS lọc theo tenant trước, rồi theo trường nghiệp vụ như status hoặc date. Mặc định tốt là index trên tenant_id, và với bảng có lưu lượng cao thì index ghép như (tenant_id, created_at) hoặc (tenant_id, status) tùy filter phổ biến.

Quyết định sớm bảng nào là global và bảng nào là tenant-scoped. Bảng global thường thấy: countries, currency codes, plan definitions. Bảng tenant-scoped: customers, invoices, tickets, và mọi thứ tenant sở hữu.

Nếu muốn bộ quy tắc dễ duy trì, giữ nó hẹp:

  • Bảng tenant-scoped: tenant_id NOT NULL, bật RLS, chính sách luôn kiểm tra tenant_id.
  • Bảng tham chiếu global: không có tenant_id, không chính sách tenant, đa phần read-only.
  • Bảng chia sẻ nhưng cần kiểm soát: tách bảng theo khái niệm (tránh trộn global và tenant rows).

Nếu bạn xây dựng với công cụ như AppMaster, nhất quán này có lợi ở mô hình dữ liệu. Khi tenant_id là trường chuẩn, bạn có thể tái dùng cùng mẫu qua các module mà không bất ngờ.

Từng bước: tạo chính sách tenant đầu tiên

Put business rules in one place
Biến vai trò, sở hữu và phê duyệt thành logic backend mà không phải viết lại kiểm soát phân quyền khắp nơi.
Tạo dự án

Một chiến thắng ban đầu với PostgreSQL RLS là chọn một bảng mà chỉ có thể đọc trong tenant hiện tại. Ý nghĩa đơn giản: ngay cả khi ai đó quên WHERE trong API, DB vẫn từ chối trả hàng của tenant khác.

Bắt đầu với bảng có tenant_id:

ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;

Khi RLS bật, hành vi mặc định thường khiến nhiều người ngạc nhiên: nếu một role bị RLS áp dụng và không có chính sách phù hợp, SELECT trả về zero rows (và ghi sẽ fail). Đó là điều bạn muốn lúc bắt đầu.

Bây giờ thêm chính sách đọc tối thiểu. Ví dụ này giả sử app của bạn đặt một session variable như app.tenant_id sau khi login:

CREATE POLICY invoices_tenant_read
ON invoices
FOR SELECT
USING (tenant_id = current_setting('app.tenant_id')::uuid);

Tiếp theo, thêm quy tắc ghi. Trong RLS, USING kiểm soát những hàng hiện có bạn có thể chạm tới, và WITH CHECK kiểm soát giá trị mới bạn được phép ghi.

CREATE POLICY invoices_tenant_insert
ON invoices
FOR INSERT
WITH CHECK (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY invoices_tenant_update
ON invoices
FOR UPDATE
USING (tenant_id = current_setting('app.tenant_id')::uuid)
WITH CHECK (tenant_id = current_setting('app.tenant_id')::uuid);

CREATE POLICY invoices_tenant_delete
ON invoices
FOR DELETE
USING (tenant_id = current_setting('app.tenant_id')::uuid);

Các chính sách mặc định là PERMISSIVE, nghĩa là bất kỳ một chính sách nào cho phép đều đủ. Chọn RESTRICTIVE khi bạn muốn mọi quy tắc đều phải thỏa (hữu ích khi thêm rào thứ hai như “chỉ tài khoản active”).

Giữ chính sách nhỏ và tập trung vào vai trò. Thay vì một quy tắc khổng lồ với nhiều OR, hãy tạo chính sách riêng cho từng đối tượng (ví dụ invoices_tenant_read_app_userinvoices_tenant_read_support_agent). Dễ test hơn, dễ review hơn và an toàn hơn khi thay đổi.

Truyền ngữ cảnh tenant và user một cách an toàn

Để PostgreSQL RLS hoạt động, DB cần biết “ai đang gọi” và “thuộc tenant nào”. Chính sách RLS chỉ có thể so sánh hàng với các giá trị mà DB có thể đọc tại thời điểm truy vấn, nên bạn phải truyền ngữ cảnh đó vào session.

Một mẫu phổ biến là đặt session variables sau khi xác thực, rồi để chính sách đọc chúng bằng current_setting(). App xác thực danh tính (ví dụ bằng cách kiểm tra JWT), rồi chỉ copy những trường cần thiết (tenant_id, user_id, role) vào kết nối DB.

-- Run once per request (or per transaction)
SELECT set_config('app.tenant_id', '3f2a0c3e-9c7b-4d3f-9c5c-3c5e9c5d1a11', true);
SELECT set_config('app.user_id',   '8d9c6b1a-6b6d-4e32-9c0d-2bfe6f6c1111', true);
SELECT set_config('app.role',      'support_agent', true);

-- In a policy
-- tenant_id column is a UUID
USING (tenant_id = current_setting('app.tenant_id', true)::uuid);

Dùng tham số thứ ba true để làm cho nó “local” với transaction hiện tại. Điều đó quan trọng nếu bạn dùng connection pooling: một connection được pool có thể được tái sử dụng cho request khác, nên bạn không muốn ngữ cảnh tenant của hôm qua còn bám lại.

Lấy ngữ cảnh từ claims JWT

Nếu API của bạn dùng JWT, hãy coi claims như dữ liệu đầu vào, không phải sự thật tuyệt đối. Xác minh chữ ký token và expiry trước, rồi chỉ copy những trường cần thiết (tenant_id, user_id, role) vào session settings. Tránh cho client gửi trực tiếp các giá trị này qua header hoặc query param.

Thiếu hoặc ngữ cảnh không hợp lệ: mặc định là từ chối

Thiết kế chính sách sao cho khi thiếu setting thì không có hàng nào được trả về.

Dùng current_setting('app.tenant_id', true) để giá trị thiếu trả về NULL. Cast về kiểu đúng (ví dụ ::uuid) để format không hợp lệ fail nhanh. Và fail request nếu không thể đặt ngữ cảnh tenant/user, thay vì đoán giá trị mặc định.

Điều này giữ kiểm soát truy cập nhất quán ngay cả khi một truy vấn bỏ qua UI hoặc một endpoint mới được thêm sau này.

Mẫu vai trò thực tế mà dễ duy trì

Build secure internal tools
Tạo hóa đơn, ticket và màn hình admin với các rào chắn phù hợp với quy tắc cơ sở dữ liệu của bạn.
Try It Now

Cách dễ nhất để giữ chính sách RLS đọc được là tách định danh khỏi quyền. Một baseline tốt là bảng users cộng bảng memberships nối user tới tenant và vai trò (hoặc nhiều vai trò). Khi đó chính sách chỉ trả lời một câu: “Người dùng hiện tại có membership phù hợp cho hàng này không?”

Giữ tên vai trò gắn với hành động thực tế, không phải chức danh công việc. “invoice_viewer” và “invoice_approver” thường bền hơn “manager”, vì chính sách có thể viết bằng ngôn ngữ rõ ràng.

Một vài mẫu vai trò dễ mở rộng:

  • Owner-only: hàng có created_by_user_id (hoặc owner_user_id) và kiểm tra truy cập khớp đúng.
  • Team-only: hàng có team_id, và chính sách kiểm tra user là thành viên của team đó trong cùng tenant.
  • Approved-only: đọc chỉ khi status = 'approved', và ghi giới hạn cho approvers.
  • Quy tắc hỗn hợp: bắt đầu nghiêm ngặt, rồi thêm ngoại lệ nhỏ (ví dụ “support có thể đọc, nhưng chỉ trong tenant”).

Admin xuyên-tenant là nơi nhiều đội dễ gặp rắc rối. Xử lý họ rõ ràng, không để như một lỗ hổng “superuser” ẩn. Tạo khái niệm riêng như platform_admin (global) và yêu cầu kiểm tra rõ ràng trong chính sách. Tốt hơn là giữ quyền đọc xuyên-tenant mặc định, và cho phép ghi phải có tiêu chuẩn cao hơn.

Tài liệu hóa quan trọng hơn bạn nghĩ. Để một comment ngắn trên mỗi chính sách giải thích ý định, không chỉ SQL. “Approvers can change status. Viewers can only read approved invoices.” Sáu tháng sau, ghi chú đó giúp sửa đổi chính sách an toàn.

Nếu bạn dùng công cụ no-code như AppMaster, các mẫu này vẫn áp dụng. UI và API có thể nhanh, nhưng quy tắc DB ổn định vì chúng dựa trên memberships và ý nghĩa vai trò rõ ràng.

Kịch bản ví dụ: một SaaS đơn giản với invoices và support

Start from a multi-tenant foundation
Bắt đầu từ cấu trúc đa-tenant rõ ràng cho SaaS và portal, sau đó tùy chỉnh vai trò và sở hữu dữ liệu.
Build With Templates

Hãy tưởng tượng một SaaS nhỏ phục vụ nhiều công ty. Mỗi công ty là một tenant. App có invoices (tiền) và support tickets (hỗ trợ hàng ngày). Người dùng có thể là agent, manager hoặc support.

Mô hình dữ liệu (đơn giản): mỗi hàng invoice và ticket có tenant_id. Tickets còn có assignee_user_id. App đặt tenant hiện tại và user vào session DB ngay sau khi login.

Đây là cách PostgreSQL RLS giảm rủi ro hàng ngày.

Một user từ Tenant A mở màn hình invoices và thử đoán một invoice ID từ Tenant B (hoặc UI gửi nhầm). Truy vấn vẫn chạy, nhưng DB trả về zero rows vì chính sách yêu cầu invoice.tenant_id = current_tenant_id. Không có rò rỉ kiểu “access denied”, chỉ là kết quả rỗng.

Trong cùng tenant, vai trò thu hẹp quyền nữa. Manager có thể thấy tất cả invoices và tickets tenant họ. Agent chỉ thấy ticket được gán cho họ, cộng có thể các nháp của chính họ. Đây là chỗ teams thường sai trong API, đặc biệt khi filters là tuỳ chọn.

Support là trường hợp đặc biệt. Họ có thể cần xem invoices để hỗ trợ khách hàng, nhưng không nên thay đổi các trường nhạy cảm như amount, bank_account, hay tax_id. Một mẫu thực tế là:

  • Cho SELECT trên invoices cho role support (vẫn bị giới hạn tenant).
  • Cho UPDATE chỉ qua đường an toàn (ví dụ một view lộ các cột được phép sửa, hoặc một update policy nghiêm ngặt từ chối thay đổi các trường được bảo vệ).

Bây giờ kịch bản “bug API vô tình”: một endpoint quên apply tenant filter sau khi refactor. Không có RLS, có thể rò rỉ invoices giữa tenant. Với RLS, DB từ chối trả hàng ngoài tenant session, nên bug chỉ làm màn hình lỗi, không thành sự cố rò rỉ dữ liệu.

Nếu bạn xây dựng loại SaaS này trong AppMaster, bạn vẫn muốn những quy tắc ở trong DB. Kiểm tra ở UI có ích, nhưng quy tắc DB là cái giữ an toàn khi có sự cố.

Những lỗi thường gặp và cách tránh

RLS mạnh, nhưng những sơ suất nhỏ có thể biến “an toàn” thành “bất ngờ”. Vấn đề thường xuất hiện khi thêm bảng mới, thay đổi vai trò, hoặc ai đó test bằng user DB sai.

Lỗi phổ biến là quên bật RLS trên bảng mới. Bạn có thể viết chính sách cẩn thận cho các bảng chính, rồi thêm một bảng “notes” hay “attachments” mà ship với quyền truy cập đầy đủ. Hãy tạo thói quen: bảng mới = bật RLS + ít nhất một chính sách.

Bẫy thường gặp khác là chính sách không đồng bộ giữa các action. Chính sách cho phép INSERT nhưng chặn SELECT có thể làm dữ liệu “biến mất” ngay sau khi tạo. Ngược lại, người dùng có thể đọc hàng họ không thể tạo nên họ sẽ bày mẹo trong UI. Hãy nghĩ theo luồng: “tạo rồi xem”, “update rồi mở lại”, “xóa rồi list”.

Cẩn trọng với SECURITY DEFINER functions. Chúng chạy với quyền chủ sở hữu function, có thể bypass RLS nếu không thận trọng. Nếu dùng, giữ chúng nhỏ, validate input, và tránh dynamic SQL trừ khi thật cần.

Cũng đừng dựa vào lọc phía app trong khi để DB mở toàn bộ. Ngay cả API làm tốt cũng sẽ có endpoint mới, job nền, script admin. Nếu role DB có thể đọc mọi thứ, sớm muộn gì cũng có chuyện xảy ra.

Để phát hiện sớm, giữ các kiểm tra thực tế:

  • Test bằng cùng DB role app production dùng, không phải user admin cá nhân.
  • Thêm một test negative cho mỗi bảng: user từ tenant khác phải thấy zero rows.
  • Xác nhận mỗi bảng hỗ trợ action mong đợi: SELECT, INSERT, UPDATE, DELETE.
  • Review việc dùng SECURITY DEFINER và document lý do cần thiết.
  • Bao gồm “RLS enabled?” trong checklist review code và migration.

Ví dụ: nếu agent tạo note invoice mà không đọc lại được, thường là thiếu SELECT policy tương ứng hoặc ngữ cảnh tenant không được đặt cho session đó.

Checklist nhanh để xác thực setup RLS

Keep UI and access aligned
Tạo web và mobile apps sao cho quyền truy cập UI khớp với quyền backend của bạn.
Build App

RLS có thể trông đúng trên giấy nhưng fail trong thực tế. Xác thực ít liên quan đến đọc chính sách và nhiều hơn đến cố gắng phá chúng với các tài khoản và truy vấn thực tế. Test theo cách app bạn sẽ dùng nó, không phải cách bạn mong muốn nó hoạt động.

Tạo một bộ test identity nhỏ trước. Dùng ít nhất hai tenant (Tenant A và Tenant B). Với mỗi tenant, thêm một user bình thường và một admin/manager. Nếu hỗ trợ role “support agent” hoặc “read-only”, thêm những role đó.

Rồi thử nghiệm RLS với bộ kiểm tra lặp lại:

  • Chạy các thao tác cốt lõi cho mỗi vai trò: liệt kê rows, fetch một row theo id, insert, update, delete. Với mỗi thao tác, thử cả trường hợp được phép và trường hợp phải bị chặn.
  • Chứng minh ranh giới tenant: dưới Tenant A, cố đọc hoặc sửa dữ liệu Tenant B bằng id bạn biết tồn tại. Bạn nên nhận zero rows hoặc permission error, không bao giờ “một số hàng”.
  • Test joins để tìm rò rỉ: join các bảng được bảo vệ vào bảng khác (bao gồm lookup). Xác nhận join không kéo row từ tenant khác qua foreign key hay view.
  • Kiểm tra thiếu hoặc sai ngữ cảnh bị từ chối: xóa ngữ cảnh tenant/user và thử lại. “Không có ngữ cảnh” nên fail đóng. Thử tenant id không hợp lệ.
  • Xác nhận hiệu năng cơ bản: xem kế hoạch truy vấn và đảm bảo index hỗ trợ mẫu lọc tenant của bạn (thường là tenant_id cộng với cột sort/search).

Nếu test nào làm bạn ngạc nhiên, sửa chính sách hoặc cách đặt ngữ cảnh trước. Đừng vá bằng UI hay API và hy vọng DB “phần lớn giữ an toàn”.

Các bước tiếp theo: triển khai an toàn và giữ nhất quán

Đối xử với PostgreSQL RLS như một hệ thống an toàn: đưa vào cẩn thận, verify thường xuyên, và giữ quy tắc đủ đơn giản để team tuân theo.

Bắt đầu nhỏ. Chọn các bảng mà rò rỉ sẽ gây hại nhất (payments, invoices, dữ liệu nhân sự, tin nhắn khách hàng), và bật RLS ở đó trước.

Thứ tự rollout thực tế thường là:

  • Bảng core “owned” trước (hàng rõ ràng thuộc về một tenant)
  • Bảng có dữ liệu cá nhân (PII)
  • Bảng chia sẻ nhưng lọc theo tenant (reports, analytics)
  • Bảng join và edge cases (many-to-many)
  • Phần còn lại khi cơ bản ổn định

Làm cho test trở thành bắt buộc. Tests tự động nên chạy cùng các truy vấn dưới các tenant và vai trò khác nhau và xác nhận thay đổi. Bao gồm cả kiểm tra “nên cho phép” và “nên từ chối”, vì lỗi cho phép quá rộng thường âm thầm đắt đỏ nhất.

Giữ một nơi rõ ràng trong luồng request để đặt session context trước khi bất kỳ truy vấn nào chạy. tenant id, user id, và role nên được áp dụng một lần, sớm, và không bao giờ đoán sau đó. Nếu bạn đặt context giữa transaction, rồi sẽ có truy vấn chạy với giá trị thiếu hoặc cũ.

Khi bạn xây dựng với AppMaster, chuẩn bị sự nhất quán giữa API backend được sinh và chính sách PostgreSQL. Chuẩn hoá cách truyền context tenant và role vào DB (ví dụ cùng session variables cho mọi endpoint) để chính sách hoạt động giống nhau khắp nơi. Nếu bạn dùng AppMaster tại appmaster.io, RLS vẫn xứng đáng được coi là thẩm quyền cuối cùng cho cô lập tenant, ngay cả khi bạn cũng kiểm soát truy cập ở UI.

Cuối cùng, để ý những gì fail. Các lỗi authorization là tín hiệu hữu ích, nhất là sau rollout. Theo dõi các denial lặp lại và điều tra xem đó là tấn công thật, luồng client hỏng, hay chính sách quá nghiêm.

Danh sách thói quen ngắn giúp RLS khỏe mạnh:

  • Tư duy mặc định là từ chối, thêm ngoại lệ có chủ đích
  • Tên chính sách rõ ràng (table + action + audience)
  • Thay đổi chính sách được review như thay đổi code
  • Ghi nhận và review denial trong giai đoạn rollout ban đầu
  • Một bộ test nhỏ thêm cho mỗi bảng mới có RLS
Dễ dàng bắt đầu
Tạo thứ gì đó tuyệt vời

Thử nghiệm với AppMaster với gói miễn phí.
Khi bạn sẵn sàng, bạn có thể chọn đăng ký phù hợp.

Bắt đầu