Giao diện
Security model
Bảo mật trong Digiforce gồm hai engine: AuthManager (xác thực - ai đang gọi) và ACL Engine (phân quyền - được làm gì). Cả hai nằm bên trong data source pipeline, không phải middleware Koa cấp app. Trang này mô tả ở mức kiến trúc; deep dive code-level: Core: ACL và Core: Auth.
1) Vị trí trong pipeline
Thứ tự trong data source pipeline (Toposort):
validate-filter-paramsauth- xác thựcResourceManager- parse resource + actionacl- phân quyền (sauauth)parseVariables,dataTemplate- Pre-action → handler
2) AuthManager - xác thực
Kiến trúc
AuthManagergiữJwtService(ký/verify JWT), map auth types, storer (đọc authenticator config từ DB).- Plugin đăng ký kiểu xác thực:
authManager.registerTypes('password', { auth: PasswordAuth, title: 'Password' }). Storerđọc collectionauthenticatorsđể lấy config cho từng kiểu auth.
Auth middleware flow
skipCheck() trả true khi:
ctx.skipAuthCheck === true, hoặc- Không có bearer token và
ctx.app.options.acl === false, hoặc - Action được ACL coi là public (
acl.allowManager.isPublic(resource, action, ctx)).
JWT lifecycle
3) ACL Engine - phân quyền
Kiến trúc
| Thành phần | Vai trò |
|---|---|
roles | Map role → ACLRole; define bằng acl.define({ role, strategy?, actions?, snippets? }). |
AllowManager | Ngoại lệ: cho phép resource/action theo điều kiện (public, loggedIn, hàm tùy chỉnh). |
SnippetManager | Nhóm quyền theo glob pattern (ui.*, pm.*); gán cho role. |
FixedParamsManager | Merge filter/params cố định vào kết quả can() (ví dụ ownedBy: currentUser). |
availableActions | Action khả dụng cho collection (export, import, …) - plugin đăng ký. |
availableStrategy | Strategy mặc định cho role (view own, edit own, …). |
Luồng can() - quyết định phân quyền
ACL middleware flow
Snippet - nhóm quyền
Snippet dùng glob pattern (minimatch) trên path resource:action:
| Snippet name | Pattern | Ý nghĩa |
|---|---|---|
ui.* | ui.* | Toàn bộ UI config actions |
pm.* | pm.* | Plugin manager actions |
!pm.remove | !pm:remove | Phủ định: cấm xóa plugin |
Role gán snippet; khi can() kiểm tra, SnippetManager match pattern.
Fixed params - filter ngầm
FixedParamsManager gộp filter vào mỗi request đã được allow. Ví dụ: role member chỉ xem record do mình tạo → fixed param .filter: { createdById: '{{ ctx.state.currentUser.id }}' }
4) Tích hợp Auth ↔ ACL
- Auth resolve
currentUservàcurrentRole(mặc địnhanonymousnếu không đăng nhập). - ACL nhận
currentRole→ kiểm tra quyền. - Action public (đăng ký qua
acl.allow) →skipCheck()= true ở Auth → ACL cũng allow.
5) Plugin plugin-acl vs core @digiforce-nc/acl
| Layer | Package | Vai trò |
|---|---|---|
| Core library | @digiforce-nc/acl | Engine in-memory: ACL, ACLRole, AllowManager, can(). |
| Plugin runtime | plugin-acl | Đồng bộ DB → ACL: đọc roles/permissions từ DB, gọi acl.define(). |
Core ACL là stateless engine - không biết database. Plugin ACL đọc cấu hình từ collection roles, rolesResources, rolesResourcesActions rồi feed vào engine.
6) Checklist bảo mật khi mở rộng
| Khi | Làm gì |
|---|---|
| Thêm resource/action mới | Đăng ký acl.allow(...) hoặc setAvailableAction để gán quyền. |
| Endpoint cần public (không auth) | acl.allow(resource, actions, 'public') - tránh dùng cho write actions. |
| Giới hạn "chỉ xem record của mình" | Fixed params: filter.createdById = currentUser.id. |
| Plugin cần snippet mới | acl.registerSnippet({ name, actions }) với glob pattern phù hợp. |
| Action ghi dữ liệu | Luôn qua ACL; dùng transaction; validate trước Repository. |
Đọc tiếp
- Tổng quan hệ thống
- Server architecture - pipeline middleware chi tiết.
- Plugin architecture - cách plugin đăng ký ACL/auth.
- Request lifecycle - sequence end-to-end.
- Core: ACL Engine - deep dive code-level.
- Core: Auth & AuthManager - deep dive code-level.