跳轉到

角色(Access Roles)

功能群:系統管理|權限模型(三段式權限名、萬用字元規則、出貨角色)先讀 功能群總覽 §2|同組頁:角色明細、指派、檢查存取

事實基準:2026-10-08 從 FE src/views/access/RoleList.vue 等 + jedi-iam api/routes/role_route.py、ui_route_route.py + BE app/auth/service/role_transfer_service.py + 本機 DEV DB 掃出。

變更紀錄

日期 FR 變更
2026-10-08 FR-132 新頁:存取管理「角色」列表,取代角色權限管理列表頁;含匯出/匯入角色 JSON

1. 功能描述

「角色」是存取管理的第一頁(側欄 存取管理 › 角色,route access-roles,/access/roles)。角色=一組權限;管理員在這裡看全部角色、建立/複製/刪除角色、預覽某角色登入後看得到的選單,並以 JSON 匯出匯入角色(跨環境搬角色)。勾選權限在 角色明細;把角色給人在 指派。

主要使用者:租戶管理員(持 iam.role.* 權限者)。

角色速覽

角色 在本頁能做什麼
持 iam.role.read 看列表、預覽可見選單、進明細檢視
另持 iam.role.create/delete/export/import 對應出現「新增角色/複製」「刪除」「匯出」「匯入角色 JSON」
系統管理員(*.*.*) 全部可做;內建系統管理員本身只能檢視、複製、匯出
沒有 iam.role.read 側欄看不到本頁,直接打網址被路由守門擋到無權限頁

1.1 功能總覽

# 功能 說明 位置 詳述
1 角色列表 一列一角色:名稱(內建帶鎖頭+「內建」標籤、停用帶「已停用」)、描述、租戶、權限數(展開後)、使用者數、最後修改(出貨角色未被改過顯示「系統建立」) 主表 §6.2
2 搜尋 依角色名稱搜尋 表頭 —
3 篩選租戶 只縮小顯示範圍;看得到哪些租戶仍由資料庫租戶隔離決定 表頭 —
4 顯示已停用 預設只列啟用中的角色 表頭 —
5 排序 名稱、使用者數、最後修改由後端排序;權限數只排本頁(數字由系統即時展開計算) 欄標題 §12
6 預覽權限 對話框列出指派此角色的人登入後可見的選單(綠點可見、灰點不可見) 每列眼睛鈕 §6.3
7 檢視/編輯 進 角色明細;內建系統管理員顯示「檢視」 每列 —
8 複製 進新增頁並以此角色為範本預填 每列 UC-ROLES-01
9 匯出 JSON(單一) 下載 role-<名稱>.json 每列 UC-ROLES-02
10 刪除 有人在用時確認框列出受影響人數;內建系統管理員無此鈕 每列 §4
11 匯出全部 目前篩選條件下的全部角色(不只本頁),存成一個檔 頁首 UC-ROLES-02
12 匯入角色 JSON 對話框選檔、顯示檔內角色、處理零命中與同名 頁首 UC-ROLES-03
13 新增角色 進新增頁 頁首 UC-ROLES-01

展開成 UC:UC-ROLES-01(新增/複製)、UC-ROLES-02(匯出)、UC-ROLES-03(匯入)。

2. Use Case

角色速覽:同 §1。

視覺慣例:菱形=判斷;紅框=擋下(標錯誤碼);綠框=成功。

UC-ROLES-01 新增或複製角色

項目 內容
角色 持 iam.role.create
前置條件 授權未到期(到期唯讀時按鈕停用並附原因)
產出後置 進 角色明細 新增模式;複製時 ?template=<uid> 預選範本、名稱預填「<原名> 複本」

UC-ROLES-02 匯出角色

項目 內容
角色 持 iam.role.export
前置條件 無
產出後置 下載 JSON:{"format_version":1,"catalog_version":N,"roles":[{name, description, is_admin, capabilities:[規則…]}]};規則原樣、不展開,不帶 id

UC-ROLES-03 匯入角色

項目 內容
角色 持 iam.role.import
前置條件 檔案是本系統匯出的 JSON
產出後置 依名稱對應建立或覆蓋角色;匯入的角色一律不是內建系統管理員
flowchart TD
  A["選擇 JSON 檔"] --> B{"檔案格式正確?"}
  B -- 否 --> E1["前端提示:檔案格式不正確"]
  B -- 是 --> C["POST /roles/import"]
  C --> D{"每條規則在本環境至少命中一項權限?"}
  D -- 否 --> E2["400 AUTH_400009<br/>整份不匯入,列出角色:規則"]
  D -- 是 --> F{"有同名角色?"}
  F -- "與內建系統管理員同名" --> G["一律另存成新角色"]
  F -- "與一般角色同名、未選處理方式" --> E3["409 AUTH_409017<br/>對話框請使用者選覆蓋或另存"]
  E3 --> C
  F -- 無/已選 --> H["建立或覆蓋"]
  G --> OK["成功:已匯入 N 個角色"]
  H --> OK

舊版本匯出的檔(catalog_version 較舊或沒帶):規則若是某項權限的舊名,先換成新名再比對。

3. 權限矩陣

操作 FE 判定 BE 強制 BE 檢查位置
進入本頁、列表 側欄可見=iam.role.read(route_capabilities ALL) iam.role.read jedi-iam api/routes/role_route.py(RolesRoute.post)
權限數、可見頁數 同上 iam.role.read ui_route_route.py(RoleStatsRoute)
預覽權限 v-can iam.role.read iam.role.read ui_route_route.py(UiRoutesVisibleRoute)
新增/複製 v-can iam.role.create iam.role.create role_route.py(RoleCreateRoute)
刪除 v-can iam.role.delete;內建不顯示 iam.role.delete;內建回 409 role_route.py(RoleRoute.delete)→ role_domain_service.py(AUTH_409019)
匯出 v-can iam.role.export iam.role.export role_route.py(RoleExportRoute)
匯入 v-can iam.role.import iam.role.import role_route.py(RoleImportRoute)

FE 與 BE 判定一致。缺權限時 BE 回 403 GRC_403022,畫面顯示「使用者不具備此操作所需的權限(需要權限:<權限名>)」。

4. 狀態機與前置條件

條件 效果 出處
roles.is_system=true(內建系統管理員) 只能檢視、複製、匯出;改、停用、刪除一律 409 AUTH_409019 jedi-iam domain/service/role_domain_service.py
roles.is_template=true(出貨範例) 與自建角色相同,可改可刪可複製 resources/roles/shipped-roles.json
roles.enable=0 預設不列;開「顯示已停用」才出現並帶「已停用」標籤 RoleList.vue(listFilters)
授權到期唯讀 複製、刪除停用,tooltip 說明原因 useLicenseReadonly
刪除有人在用的角色 確認框說明「目前指派給 N 位使用者,刪除後失去此角色的權限」 RoleList.vue(confirmDelete)

出貨角色(乾淨安裝與升級都帶入,來源 resources/roles/shipped-roles.json):

角色 規則 可改
系統管理員 *.*.* 否,每租戶恰一個
稽核主管 grc.*.*、oscal.*.*、asset.*.*、evidence.*.*、detection.*.*、survey.*.* 等 可改可刪
稽核員 讀全部業務資料;任務只有檢視與修改;稽核可建立、修改、匯入 可改可刪
一般成員 讀業務資料;任務檢視與修改、留言、證據 可改可刪
唯讀 逐模組列 read(不用 *.*.read,避免日後新模組自動被讀) 可改可刪

四個範例角色都不給 workspace.feedback.export。

5. UI 設計

單頁:頁首(標題+一句說明+「匯出全部」「匯入角色 JSON」「新增角色」)、表頭工具列(搜尋、租戶篩選、顯示已停用開關)、DataTable(分頁)。對話框兩個:預覽權限(可見選單樹)、匯入角色 JSON(虛線層)。

📸 實機截圖待補(亮色模式):列表整頁、預覽權限對話框、匯入對話框(零命中清單/同名選項兩種狀態)。

介面用語:對使用者一律說「權限」「項」,不出現「能力點」「pattern」「capability」。

6. API 規格

6.1 總清單

分類 Method + Path 說明 守門
列表 POST /api/1.0/roles 分頁+篩選(name、tenant_id、enable、is_delete) iam.role.read
統計 POST /api/1.0/roles/stats 每角色展開後權限數、可見頁數、每條規則展開幾項 iam.role.read
預覽 POST /api/1.0/ui-routes/visible-by-capabilities 給權限名或角色,回可見頁 iam.role.read
刪除 DELETE /api/1.0/role/<uid> 硬刪除 iam.role.delete
匯出 POST /api/1.0/roles/export {uids:[...]} iam.role.export
匯入 POST /api/1.0/roles/import 見 §6.4 iam.role.import
下拉 GET /api/1.0/tenants/menu 租戶篩選 登入即可

6.2 列表回應(RoleResponse)

欄位 型別 說明
uid / name / description string
enable int 1 啟用、0 停用
is_admin int 管理員旗標(升級前的管理員角色保留)
is_system bool 內建系統管理員
is_template bool 出貨範例
tenant_id / tenant int / object 所屬租戶
capability_patterns list[string] 角色存的規則原樣
user_count int 指派人數
updated_user / updated_user_name / updated_at 審計欄位(updated_user='system'=出貨後未被改過)

出處:jedi-iam api/serializers/role.py(RoleResponse)。

6.3 統計回應(/roles/stats)

Request:{"uids": [...], "tenant_id": 102}——展開結果依角色所屬租戶而定(原廠租戶多原廠權限),前端同租戶的角色一次問。

欄位 型別 說明
uid string
capability_count int 規則展開後實際權限數
visible_page_count int 可見頁數(與側欄同一條判定,含授權照過濾)
pattern_counts dict 每條規則展開幾項

6.4 匯入(/roles/import)

{
  "format_version": 1,
  "catalog_version": 3,
  "roles": [
    {"name": "稽核員", "description": "…", "is_admin": 0, "capabilities": ["grc.*.read", "grc.job.update"]}
  ],
  "on_conflict": "save_as_new"
}
欄位 說明
on_conflict overwrite/save_as_new;不帶且有同名回 409
回應 roles 每個匯入結果
錯誤碼 HTTP 情境
AUTH_400009 400 有規則在本環境命中零項權限;data.unmatched=[{role, pattern}],整份不匯入
AUTH_400010 400 on_conflict 值不對
AUTH_400011 400 檔內沒有角色或名稱重複
AUTH_409017 409 與既有一般角色同名、未選處理方式
LICENSE_403004 403 角色含未授權模組的權限

出處:BE app/auth/service/role_transfer_service.py;錯誤碼 jedi-iam common/enum/error_code.py。

7. 前端檔案地圖(compliance-manager-fe/)

檔案 角色
src/views/access/RoleList.vue 列表頁
src/views/access/RolePreviewDialog.vue 預覽權限對話框
src/views/access/RoleImportDialog.vue 匯入對話框(零命中、同名兩種回應自行呈現,不 toast)
src/service/RoleAccessService.js 列表、統計、匯出入 API
src/components/access/VisibleMenuPreview.vue 可見選單樹(預覽與明細共用)
src/config/router/index.js access-roles;舊網址 /auth/role-manage、/auth/role-form 轉址到本頁與明細

8. 後端檔案地圖

鏈路 Route Service 底層
列表 jedi-iam role_route.py RolesRoute BE app/auth/service/role_app_service.py(補審計暱稱) jedi-iam role repo
統計/預覽 jedi-iam ui_route_route.py jedi-iam ui_route_service、capability_expansion_service Redis 快取(鍵含權限目錄版本號)
匯出入 jedi-iam role_route.py BE app/auth/service/role_transfer_service.py(展開後交 role_app_service 過授權照守門) jedi-iam shipped_role_writer 寫規則表

9. DB

表 讀寫 說明
public.roles 讀/寫(刪除、匯入) is_system、is_template、enable、tenant_id
public.role_capability_patterns 讀/寫(匯入) role_id × pattern;判定唯一來源
public.capabilities 讀 展開萬用字元、命中檢查、舊名對照(legacy_name)
public.user_roles 讀 使用者數

欄位說明見 角色明細 §9。

10. 頁面邏輯與資料對應

載入:POST /roles(分頁)→ 依租戶分組各打一次 POST /roles/stats → 併回每列 capability_count。切「顯示已停用」或租戶篩選回第一頁重載。

畫面元素 API 欄位
名稱旁鎖頭 is_system
權限數 stats capability_count
最後修改 updated_at + updated_user_name(updated_user='system' 顯示「系統建立」)

11. 背景行為與外部依賴

類型 內容
快取 規則展開結果存 Redis,鍵含權限目錄版本號;權限目錄變動即換鍵
socket/排程 無
套件 jedi-iam(角色、指派、判定)

12. 邊界情況與已知坑

  1. 權限數欄只排本頁:數字由 /roles/stats 即時展開,不是資料庫欄位,無法跨頁排序;欄標題 tooltip 有說明。
  2. 刪除是硬刪除:刪除後該角色的指派一併失效,使用者重新登入後即失去相關權限。
  3. 匯入零命中整份擋下:任何一條規則在本環境命中零項就整份不匯入——靜默跳過會讓匯入後的角色比來源少權限而沒人發現。
  4. 匯入不碰授權照:含未授權模組權限時由角色寫入端的授權照守門擋(LICENSE_403004)。

13. 開發與驗證