ADR-0002. RBAC qua Casbin + bảng cạnh PolicyDefinition
| Trường | Giá trị |
|---|---|
| Trạng thái | Accepted |
| Ngày | 2026-02-04 |
| Người quyết định | Phat Nguyen |
| Thay thế | - |
Bối cảnh
- Cần một mô hình RBAC linh hoạt hỗ trợ:
- Role hệ thống cố định (SUPER_ADMIN, ADMIN, OPERATOR, OWNER, CASHIER, EMPLOYEE, CUSTOMER, GUEST)
- Role tuỳ chỉnh cho merchant
- Cấp permission (Role → Permission)
- Scoping (User có thể là SCOPED_OWNER cho organizer X nhưng EMPLOYEE cho organizer Y)
- Hai cách tiếp cận tự nhiên:
- Ba bảng: User_Role, Role_Permission, cộng thêm scoping riêng
- Một bảng cạnh đơn với tính đa hình
subject+target
Quyết định
Dùng một bảng cạnh PolicyDefinition duy nhất mà variant chọn một trong tám cạnh. ScopedCasbinAdapter (@venizia/ignis) lọc các row của một principal và emit Casbin line tương ứng cho mô hình scoped-RBAC CASBIN_RBAC_DOMAIN_SCOPED_MODEL.
| Variant | Subject → Target | Casbin | Mục đích |
|---|---|---|---|
grant | Role|User → Permission | p | "subject này có thể <action> <resource>" |
assign_role | User → Role | g | "user có role" (scope theo domain; null ⇒ mọi domain) |
join_domain | User → Merchant|Organizer | g2 | membership; cấp năng lượng cho grant ANY_MEMBER |
role_inherits | Role → Role | g | DAG role |
domain_inherits | domain → domain | g3 | Merchant ⊂ Organizer / Branch ⊂ Company |
resource_inherits | resource → resource | g4 | cây obj |
action_inherits | action → action | g5 | manage ⊃ read/write/execute |
merchant_role | Role ↔ Merchant | - | metadata UI của @nx/core (adapter không đọc) |
domain của một grant mang scope - SYSTEM_WIDE, ANY_MEMBER, hoặc <Type>_<id> cụ thể (cũng phủ các child lồng qua g3). Effect là default-DENY với deny tường minh override. Thay đổi từng cạnh có hiệu lực ở lần cache enforcer hết hạn kế tiếp.
Hệ quả
| Ưu | Nhược |
|---|---|
| Một bảng cho mọi cạnh RBAC; truy vấn đồng nhất | Đa hình - không có FK ở mức DB tới subject/target |
Scope domain ANY_MEMBER / <Type>_<id> cho phép một user có role khác nhau theo từng merchant/organizer | Chi phí đánh giá của Casbin tăng theo số cạnh |
| Role tuỳ chỉnh của merchant là công dân hạng nhất (không hard-code) | Độ trễ kiểm tra permission đòi hỏi cache Redis cho line set theo từng user |
Phân cấp resource/action/domain (g3/g4/g5) giữ grant coarse - một grant module cascade xuống mọi subject/operation/child-domain | Việc rà soát/so sánh "ai có thể làm X" cần duyệt đồ thị |
Phương án đã xem xét
| Phương án | Ưu | Nhược | Lý do từ chối |
|---|---|---|---|
| Ba bảng (UserRole, RolePermission) | Ngữ nghĩa rõ ràng | Thêm hai migration + đường ghi song song | Bảo trì kém hơn |
| Một tập permission jsonb trên mỗi User | Đọc nhanh | Không có lịch sử; không kế thừa nhóm; không thể truy vấn "ai có X" | Sai nguyên thuỷ |
| Spicedb / authz bên ngoài | Tiêu chuẩn ngành | Chi phí vận hành; độ trễ nhà cung cấp | Quá sớm so với quy mô |
Tham chiếu
core/src/models/schemas/identity/policy-definition/schema.ts@nx/corecommon/policy-variant.ts(PolicyVariants)services/policy-definition/- 4 bộ ghi chuyên biệt@venizia/ignis.../enforcers/models/rbac-domain.model.ts(CASBIN_RBAC_DOMAIN_SCOPED_MODEL)