Thiết kế DB Hệ thống Phân quyền IAM
Thiết kế DB Hệ thống Phân quyền IAM (Identity and Access Management)

1. Tổng quan Hệ thống
Hệ thống IAM này được thiết kế theo mô hình phân quyền dựa trên Role-Based Access Control (RBAC) kết hợp với Record-Level Security. Hệ thống cho phép quản lý người dùng, công ty, nhóm quyền, và kiểm soát truy cập chi tiết đến từng model và bản ghi cụ thể.
Các thành phần chính:
- Quản lý Người dùng & Công ty: User, Company và mối quan hệ đa-đa giữa chúng
- Quản lý Nhóm quyền: Group và cơ chế kế thừa quyền
- Kiểm soát truy cập Model: Phân quyền CRUD trên toàn bộ model
- Kiểm soát truy cập Record: Phân quyền chi tiết đến từng bản ghi theo điều kiện
2. Chi tiết các Bảng
2.1. IAM_USER - Bảng Người dùng
Mục đích: Lưu trữ thông tin tài khoản người dùng trong hệ thống.
| Cột | Kiểu dữ liệu | Ràng buộc | Mô tả |
|---|---|---|---|
id |
bigint | PK | Mã định danh duy nhất của người dùng |
email |
text | NOT NULL, UNIQUE | Địa chỉ email đăng nhập |
password_hash |
text | NOT NULL | Mật khẩu đã được băm (bcrypt/argon2) |
is_active |
boolean | DEFAULT true | Trạng thái kích hoạt tài khoản |
company_id |
bigint | FK → IAM_COMPANY(id) | Công ty hiện tại của user (quan hệ N:1) |
created_at |
timestamptz | DEFAULT now() | Thời điểm tạo tài khoản |
Lưu ý quan trọng:
- Một user có thể thuộc nhiều company (qua
IAM_USER_COMPANY) company_idtrong bảng này là company "hiện tại" đang làm việc- Email phải unique trong toàn hệ thống
2.2. IAM_COMPANY - Bảng Công ty
Mục đích: Quản lý thông tin các công ty/tổ chức trong hệ thống multi-tenant.
| Cột | Kiểu dữ liệu | Ràng buộc | Mô tả |
|---|---|---|---|
id |
bigint | PK | Mã định danh công ty |
name |
text | NOT NULL | Tên công ty |
created_at |
timestamptz | DEFAULT now() | Thời điểm tạo |
Use case:
- Hỗ trợ multi-tenancy: phân tách dữ liệu giữa các công ty
- Một user có thể làm việc cho nhiều công ty khác nhau
2.3. IAM_USER_COMPANY - Bảng Quan hệ User-Company (Many-to-Many)
Mục đích: Liên kết người dùng với các công ty mà họ có quyền truy cập.
| Cột | Kiểu dữ liệu | Ràng buộc | Mô tả |
|---|---|---|---|
user_id |
bigint | PK, FK → IAM_USER(id) | Mã người dùng |
company_id |
bigint | PK, FK → IAM_COMPANY(id) | Mã công ty |
Composite Primary Key: (user_id, company_id)
Ví dụ:
-- User A làm việc cho cả Company 1 và Company 2
INSERT INTO IAM_USER_COMPANY VALUES (1, 1), (1, 2);
2.4. IAM_GROUP - Bảng Nhóm Quyền
Mục đích: Định nghĩa các nhóm quyền (roles) trong hệ thống.
| Cột | Kiểu dữ liệu | Ràng buộc | Mô tả |
|---|---|---|---|
id |
bigint | PK | Mã định danh nhóm |
code |
text | UNIQUE, NOT NULL | Mã code nhóm (system_admin, sales_manager...) |
name |
text | NOT NULL | Tên hiển thị của nhóm |
category |
text | Phân loại nhóm (system, business, technical...) | |
created_at |
timestamptz | DEFAULT now() | Thời điểm tạo |
Ví dụ các nhóm thường gặp:
system_admin- Quản trị viên hệ thốngcompany_admin- Quản trị công tysales_manager- Quản lý bán hàngaccountant- Kế toánemployee- Nhân viên thông thường
2.5. IAM_USER_GROUP - Bảng Gán User vào Group
Mục đích: Liên kết người dùng với các nhóm quyền.
| Cột | Kiểu dữ liệu | Ràng buộc | Mô tả |
|---|---|---|---|
user_id |
bigint | PK, FK → IAM_USER(id) | Mã người dùng |
group_id |
bigint | PK, FK → IAM_GROUP(id) | Mã nhóm quyền |
Composite Primary Key: (user_id, group_id)
Use case:
- Một user có thể thuộc nhiều group
- Một group có thể chứa nhiều user
2.6. IAM_GROUP_IMPLIED - Bảng Kế thừa Quyền giữa các Group
Mục đích: Định nghĩa mối quan hệ kế thừa quyền giữa các nhóm (role hierarchy).
| Cột | Kiểu dữ liệu | Ràng buộc | Mô tả |
|---|---|---|---|
group_id |
bigint | PK, FK → IAM_GROUP(id) | Nhóm cha (kế thừa quyền) |
implied_group_id |
bigint | PK, FK → IAM_GROUP(id) | Nhóm con (được kế thừa) |
Composite Primary Key: (group_id, implied_group_id)
Cơ chế hoạt động:
Nếu Group A implies Group B:
→ User thuộc Group A sẽ tự động có TẤT CẢ quyền của Group B
Ví dụ:
-- System Admin kế thừa tất cả quyền của Company Admin
INSERT INTO IAM_GROUP_IMPLIED VALUES
(1, 2); -- group_id=1 (system_admin) implies group_id=2 (company_admin)
-- Company Admin kế thừa quyền của Employee
INSERT INTO IAM_GROUP_IMPLIED VALUES
(2, 3); -- group_id=2 (company_admin) implies group_id=3 (employee)
-- Kết quả: System Admin có quyền của cả Company Admin VÀ Employee
2.7. IAM_MODEL - Bảng Định nghĩa Model
Mục đích: Lưu trữ danh sách các model (bảng/entity) trong hệ thống cần được quản lý quyền.
| Cột | Kiểu dữ liệu | Ràng buộc | Mô tả |
|---|---|---|---|
id |
bigint | PK | Mã định danh model |
model |
text | UNIQUE, NOT NULL | Tên kỹ thuật của model (sale.order, product.product) |
name |
text | NOT NULL | Tên hiển thị của model (Sales Order, Product) |
Ví dụ:
INSERT INTO IAM_MODEL (model, name) VALUES
('sale.order', 'Sales Order'),
('product.product', 'Product'),
('account.invoice', 'Invoice');
2.8. IAM_MODEL_ACCESS - Bảng Phân quyền Model-Level
Mục đích: Định nghĩa quyền CRUD cho từng nhóm trên từng model.
| Cột | Kiểu dữ liệu | Ràng buộc | Mô tả |
|---|---|---|---|
id |
bigint | PK | Mã định danh |
model_id |
bigint | FK → IAM_MODEL(id) | Model được phân quyền |
group_id |
bigint | FK → IAM_GROUP(id) | Nhóm được cấp quyền |
perm_read |
boolean | DEFAULT false | Quyền đọc (SELECT) |
perm_write |
boolean | DEFAULT false | Quyền sửa (UPDATE) |
perm_create |
boolean | DEFAULT false | Quyền tạo mới (INSERT) |
perm_unlink |
boolean | DEFAULT false | Quyền xóa (DELETE) |
active |
boolean | DEFAULT true | Trạng thái kích hoạt rule |
Unique Constraint: (model_id, group_id)
Ví dụ:
-- Sales Manager có full quyền trên Sales Order
INSERT INTO IAM_MODEL_ACCESS
(model_id, group_id, perm_read, perm_write, perm_create, perm_unlink)
VALUES
(1, 2, true, true, true, true);
-- Employee chỉ có quyền đọc Sales Order
INSERT INTO IAM_MODEL_ACCESS
(model_id, group_id, perm_read, perm_write, perm_create, perm_unlink)
VALUES
(1, 3, true, false, false, false);
2.9. IAM_RECORD_RULE - Bảng Quy tắc Record-Level Security
Mục đích: Định nghĩa các điều kiện lọc bản ghi (row-level security) cho từng model.
| Cột | Kiểu dữ liệu | Ràng buộc | Mô tả |
|---|---|---|---|
id |
bigint | PK | Mã định danh rule |
model_id |
bigint | FK → IAM_MODEL(id) | Model áp dụng rule |
name |
text | NOT NULL | Tên mô tả rule |
domain |
jsonb | Điều kiện lọc dạng domain filter (JSON) | |
perm_read |
boolean | DEFAULT false | Quyền đọc các bản ghi thỏa điều kiện |
perm_write |
boolean | DEFAULT false | Quyền sửa các bản ghi thỏa điều kiện |
perm_create |
boolean | DEFAULT false | Quyền tạo bản ghi mới |
perm_unlink |
boolean | DEFAULT false | Quyền xóa các bản ghi thỏa điều kiện |
is_global |
boolean | DEFAULT false | Rule áp dụng cho toàn bộ user hay chỉ các group cụ thể |
active |
boolean | DEFAULT true | Trạng thái kích hoạt |
Cấu trúc Domain Filter (JSONB):
[
["field_name", "operator", "value"],
["user_id", "=", "current_user_id"],
["company_id", "=", "current_company_id"]
]
Ví dụ:
-- Rule: Sales Manager chỉ thấy đơn hàng của công ty mình
INSERT INTO IAM_RECORD_RULE
(model_id, name, domain, perm_read, perm_write, is_global)
VALUES
(1, 'Own Company Orders Only',
'[["company_id", "=", "current_company_id"]]'::jsonb,
true, true, false);
-- Rule: Nhân viên chỉ thấy đơn hàng của chính mình
INSERT INTO IAM_RECORD_RULE
(model_id, name, domain, perm_read, is_global)
VALUES
(1, 'Own Orders Only',
'[["salesperson_id", "=", "current_user_id"]]'::jsonb,
true, false);
2.10. IAM_RECORD_RULE_GROUP - Bảng Gán Rule cho Group
Mục đích: Liên kết các record rule với các nhóm quyền.
| Cột | Kiểu dữ liệu | Ràng buộc | Mô tả |
|---|---|---|---|
rule_id |
bigint | PK, FK → IAM_RECORD_RULE(id) | Mã rule |
group_id |
bigint | PK, FK → IAM_GROUP(id) | Mã nhóm áp dụng |
Composite Primary Key: (rule_id, group_id)
Use case:
- Một rule có thể áp dụng cho nhiều group
- Một group có thể có nhiều rule khác nhau
3. Luồng Kiểm tra Quyền (Authorization Flow)
3.1. Kiểm tra Quyền Model-Level
1. User đăng nhập → Lấy danh sách Groups của user (qua IAM_USER_GROUP)
2. Áp dụng Group Inheritance (qua IAM_GROUP_IMPLIED)
→ Tạo danh sách "Effective Groups"
3. Kiểm tra IAM_MODEL_ACCESS:
- Lọc theo model_id và effective groups
- Tổng hợp quyền: Nếu BẤT KỲ group nào có quyền → User có quyền đó
4. Kết quả: {read: true, write: false, create: true, unlink: false}
3.2. Kiểm tra Quyền Record-Level
1. Sau khi pass qua Model-Level check
2. Lấy tất cả Record Rules áp dụng cho model và effective groups
3. Với mỗi operation (read/write/create/delete):
a. Lọc các rules có quyền tương ứng = true
b. Tổng hợp tất cả domain filters bằng OR logic
c. Áp dụng filter vào SQL query
4. Kết quả: SQL với WHERE clause đã được inject domain filters
Ví dụ SQL được sinh ra:
-- User thuộc group "Sales Manager"
-- Rule: Chỉ xem đơn hàng của công ty mình
SELECT * FROM sale_order
WHERE company_id = 1 -- Từ record rule domain
AND is_deleted = false;
4. Các Trường hợp Sử dụng Thực tế
Case 1: Multi-Tenant với phân quyền theo công ty
-- Tạo 2 công ty
INSERT INTO IAM_COMPANY (name) VALUES ('Company A'), ('Company B');
-- User 1 làm việc cho cả 2 công ty, nhưng hiện đang ở Company A
INSERT INTO IAM_USER (email, password_hash, company_id)
VALUES ('user1@example.com', 'hash', 1);
INSERT INTO IAM_USER_COMPANY VALUES (1, 1), (1, 2);
-- Record Rule: Chỉ xem data của công ty hiện tại
INSERT INTO IAM_RECORD_RULE (model_id, name, domain, perm_read)
VALUES (1, 'Current Company Only',
'[["company_id", "=", "current_company_id"]]'::jsonb, true);
Case 2: Phân cấp quyền theo vai trò
-- Tạo hierarchy: Admin > Manager > Employee
INSERT INTO IAM_GROUP (code, name) VALUES
('admin', 'Administrator'),
('manager', 'Manager'),
('employee', 'Employee');
-- Admin kế thừa quyền Manager
INSERT INTO IAM_GROUP_IMPLIED VALUES (1, 2);
-- Manager kế thừa quyền Employee
INSERT INTO IAM_GROUP_IMPLIED VALUES (2, 3);
-- Employee: Chỉ đọc
INSERT INTO IAM_MODEL_ACCESS (model_id, group_id, perm_read)
VALUES (1, 3, true);
-- Manager: Đọc + Ghi
INSERT INTO IAM_MODEL_ACCESS (model_id, group_id, perm_read, perm_write)
VALUES (1, 2, true, true);
-- Admin: Full quyền (kế thừa read+write từ Manager, tự có create+delete)
INSERT INTO IAM_MODEL_ACCESS (model_id, group_id, perm_create, perm_unlink)
VALUES (1, 1, true, true);
Case 3: Nhân viên chỉ xem data của mình
-- Record Rule: Salesperson chỉ xem đơn hàng của mình
INSERT INTO IAM_RECORD_RULE (model_id, name, domain, perm_read, perm_write)
VALUES (1, 'Own Sales Only',
'[["salesperson_id", "=", "current_user_id"]]'::jsonb,
true, true);
-- Gán rule cho nhóm "Salesperson"
INSERT INTO IAM_RECORD_RULE_GROUP VALUES (1, 4);
5. Lưu ý Thiết kế & Best Practices
5.1. Performance Considerations
-
Index quan trọng:
CREATE INDEX idx_user_group ON IAM_USER_GROUP(user_id); CREATE INDEX idx_model_access ON IAM_MODEL_ACCESS(model_id, group_id); CREATE INDEX idx_record_rule_group ON IAM_RECORD_RULE_GROUP(group_id); CREATE INDEX idx_record_rule_domain ON IAM_RECORD_RULE USING gin(domain); -
Cache effective groups: Tính toán trước và cache danh sách groups (kể cả implied) của mỗi user
5.2. Security Best Practices
- Principle of Least Privilege: Mặc định tất cả permissions = false
- Explicit Deny: Không có permission = deny, không cần "deny rule"
- Audit Trail: Nên thêm các cột
created_by,updated_at,updated_bycho audit
5.3. Domain Filter Guidelines
- Hỗ trợ các operator:
=,!=,>,<,>=,<=,in,not in,like,ilike - Hỗ trợ các biến động:
current_user_id,current_company_id,current_date - Sử dụng AND/OR logic kết hợp:
[ "&", // AND operator ["company_id", "=", "current_company_id"], "|", // OR operator ["manager_id", "=", "current_user_id"], ["salesperson_id", "=", "current_user_id"] ]
5.4. Soft Delete
Nên implement soft delete cho tất cả các bảng phân quyền:
ALTER TABLE IAM_MODEL_ACCESS ADD COLUMN deleted_at timestamptz;
ALTER TABLE IAM_RECORD_RULE ADD COLUMN deleted_at timestamptz;
6. Migration & Seeding Strategy
6.1. Thứ tự Migration
- IAM_COMPANY
- IAM_USER
- IAM_USER_COMPANY
- IAM_GROUP
- IAM_USER_GROUP
- IAM_GROUP_IMPLIED
- IAM_MODEL
- IAM_MODEL_ACCESS
- IAM_RECORD_RULE
- IAM_RECORD_RULE_GROUP
6.2. Seed Data Cơ bản
-- 1. Tạo System Admin Group
INSERT INTO IAM_GROUP (code, name, category)
VALUES ('system_admin', 'System Administrator', 'system');
-- 2. Tạo default company
INSERT INTO IAM_COMPANY (name) VALUES ('Default Company');
-- 3. Tạo super admin user
INSERT INTO IAM_USER (email, password_hash, company_id, is_active)
VALUES ('admin@system.com', 'hashed_password', 1, true);
-- 4. Gán user vào System Admin group
INSERT INTO IAM_USER_GROUP VALUES (1, 1);
-- 5. Cấp full quyền cho System Admin trên tất cả models
INSERT INTO IAM_MODEL_ACCESS (model_id, group_id, perm_read, perm_write, perm_create, perm_unlink)
SELECT id, 1, true, true, true, true FROM IAM_MODEL;
7. Mở rộng & Tính năng Nâng cao
7.1. Field-Level Security (Tương lai)
Có thể mở rộng với bảng:
CREATE TABLE IAM_FIELD_ACCESS (
id bigint PRIMARY KEY,
model_id bigint REFERENCES IAM_MODEL(id),
field_name text,
group_id bigint REFERENCES IAM_GROUP(id),
perm_read boolean,
perm_write boolean
);
7.2. Time-Based Access Control
Thêm cột vào IAM_MODEL_ACCESS:
ALTER TABLE IAM_MODEL_ACCESS
ADD COLUMN valid_from timestamptz,
ADD COLUMN valid_until timestamptz;
7.3. Delegation & Temporary Access
CREATE TABLE IAM_USER_DELEGATION (
id bigint PRIMARY KEY,
delegator_user_id bigint,
delegate_user_id bigint,
valid_from timestamptz,
valid_until timestamptz
);
Hệ thống phân quyền này cung cấp khả năng kiểm soát truy cập linh hoạt từ model-level đến record-level, hỗ trợ multi-tenancy, và có khả năng mở rộng cao cho các hệ thống enterprise.
All rights reserved