隨著系統成長,權限管理會漸漸失控。
一開始或許只是幾個簡單的判斷式:
if (user.isAdmin) { ... }
if (user.permission.includes("deletePost")) { ... }
但當功能越來越多、角色越來越複雜。
結果是:
RBAC(Role-Based Access Control,角色基礎存取控制)
正是為了解決這個問題而誕生的架構。
它將權限管理「結構化、模組化」,
讓程式乾淨、邏輯一致,並且能隨需求成長。
RBAC 的核心邏輯:
使用者(User)不直接擁有權限,而是透過角色(Role)間接取得權限(Permission)。
換句話說,你不用在每個人身上設定權限,
而是設定角色 → 然後把使用者指派到角色。
User → Role → Permission
這樣的架構設計有兩大優點:
RBAC 並不只是後端的概念,而是在整個系統中的權限管控。
解決:「能不能做」的問題。
最直接的 RBAC 用法:
控制某個角色能否呼叫某個 API、使用某個功能。
角色 | 可執行功能 |
---|---|
Admin | 建立/編輯/刪除使用者 |
Editor | 新增/修改文章 |
Viewer | 僅可瀏覽 |
後端通常透過 Middleware 來檢查:
router.post("/posts", verifyToken, authorizeRoles("editor", "admin"), createPost);
✅ 有權限 → 放行
🚫 沒權限 → 回傳 403 Forbidden
解決:「能看到多少」的問題。
登入不代表可以看全部資料。
我們常需根據角色決定資料範圍:
實作上,就是在查詢時加入條件限制:
const posts = await Post.find({ authorId: req.user.id });
RBAC 不只管「能不能用哪些功能」,還可管「能看到哪些資料」。
解決:「要不要顯示」的問題。
前端也該尊重權限設定。
讓不同角色看到不同畫面,能有效防止誤操作。
角色 | 顯示畫面 |
---|---|
Admin | 使用者管理按鈕 |
Editor | 發表文章按鈕 |
Viewer | 只讀畫面 |
但要記得:
即使前端隱藏按鈕,後端仍要驗證。
真正的授權判斷必須在伺服器端完成。
RBAC 通常可分成五張主要資料表(或集合):
Collection | 說明 |
---|---|
users |
使用者資料 |
roles |
角色定義(admin/editor/viewer) |
permissions |
權限定義(如 createPost、deleteUser) |
user_roles |
使用者與角色關聯 |
role_permissions |
角色與權限關聯 |
這樣的設計能達到:
// User
{
"_id": "u01",
"username": "alice",
"roles": ["editor"]
}
// Role
{
"_id": "r01",
"name": "editor",
"permissions": ["create:post", "edit:post"]
}
// Permission
{
"_id": "p01",
"name": "create:post"
}
實際查詢流程:
const user = await User.findOne({ username: "alice" }).populate("roles");
const role = await Role.findOne({ name: user.roles[0] });
if (role.permissions.includes("create:post")) {
// ✅ 有權限,放行
}
優點 | 說明 |
---|---|
結構清晰 | 權限集中管理,不再散落程式各處 |
容易維護 | 調整角色或權限不需改程式碼 |
高安全性 | 落實最小權限原則(Least Privilege) |
可稽核性強 | 可追蹤誰擁有什麼權限 |
與 JWT 結合自然 | Token 可攜帶角色資訊,API 驗證快速輕量 |
RBAC 的核心價值不只是「多幾個角色」,
而是讓整個系統擁有可觀察、可維護、可審計的權限結構。
它能夠讓你的系統做到:
1️⃣ 誰可以執行什麼功能?(功能層)
2️⃣ 誰可以看到哪些資料?(資料層)
3️⃣ 誰應該看到哪些畫面?(介面層)
今天有了基礎的RBA概念後,明日我們就來運用這概念搭配上API的實作吧!