指派(Role Assignments)¶
功能群:系統管理|權限模型先讀 功能群總覽 §2|同組頁:角色、檢查存取(嵌在本頁頂部)
事實基準:2026-10-08 從 FE
src/views/access/AssignmentManage.vue、AssignmentDialog.vue、assignmentPeriod.js+ jedi-iamapi/routes/role_assignment_route.py、app/service/role_assignment_service.py+ 本機 DEV DB 掃出。
變更紀錄¶
| 日期 | FR | 變更 |
|---|---|---|
| 2026-10-08 | FR-132 | 新頁:一筆指派=某人 × 某角色 × 範圍 × 期間;到期自動失效;頂部嵌檢查存取 |
1. 功能描述¶
指派頁(側欄 存取管理 › 指派,route access-assignments,/access/assignments)列出「誰在什麼期間擁有哪個角色」。一筆指派=使用者 × 角色 × 範圍(租戶/部門)× 起訖日。到期的指派不用手動移除:仍列在表上並標「已到期」,但權限判定與側欄選單不再採計。頂部的「檢查存取」搜尋框可以查單一使用者實際擁有的權限,見 檢查存取。
範圍:畫面一律建「整個租戶」範圍的指派。資料表與 API 保留部門範圍(scope=org_unit、org_unit_id),但部門目前只當屬性記錄,判定上與整個租戶相同——部門資料隔離本版不做。
主要使用者:租戶管理員。
角色速覽
| 角色 | 在本頁能做什麼 |
|---|---|
持 iam.user.read |
看指派表、檢查存取 |
另持 iam.user.assign |
新增、編輯期間、移除指派 |
沒有 iam.user.read |
側欄看不到;直接進頁顯示「目前帳號沒有檢視指派的權限」 |
1.1 功能總覽¶
| # | 功能 | 說明 | 位置 | 詳述 |
|---|---|---|---|---|
| 1 | 檢查存取 | 輸入姓名或帳號,表格區切成該人的權限來源與可見選單 | 頁首下方 | 檢查存取 |
| 2 | 指派表 | 使用者、角色、生效、到期(空=永久)、狀態 | 主表 | §6.2 |
| 3 | 依人/依角色 | 同一張表換分組列(分組列顯示筆數) | 工具列 | — |
| 4 | 角色篩選 | 只看某角色;從 角色明細「檢視指派清單」進來時已預選 | 工具列 | — |
| 5 | 只看某人 | 網址帶 ?user_uid= 時出現可移除的「僅檢視:<姓名>」標籤 |
工具列 | — |
| 6 | 顯示已到期 | 預設隱藏;表尾提示「另有 N 筆已到期未顯示」 | 工具列 | §4 |
| 7 | 新增指派 | 對話框:選人(可多選)、角色、期間;右側預覽可見選單變化 | 頁首 | UC-ASSIGN-01 |
| 8 | 編輯期間 | 只改起訖;換人或換角色請移除後重建 | 每列 | UC-ASSIGN-02 |
| 9 | 移除指派 | 確認後刪除;移除後重新登入就無法使用相關功能 | 每列 | — |
2. Use Case¶
角色速覽:同 §1。
UC-ASSIGN-01 新增指派¶
| 項目 | 內容 |
|---|---|
| 角色 | 持 iam.user.assign |
| 前置條件 | 被指派者是角色所屬租戶的成員;一次只選同一租戶的人 |
| 產出後置 | 每位使用者各一筆 user_roles(scope=tenant) |
flowchart TD
A["選人(可多選)"] --> B{"都在同一租戶?"}
B -- 否 --> X0["提示:請一次只選同一個租戶的人"]
B -- 是 --> C["角色下拉只列該租戶角色<br/>選角色、期間(永久/指定起訖)"]
C --> P["右側預覽:目前已可見(灰)+加上此角色後新增(綠)"]
P --> D["建立指派:每人各送一次 POST /role-assignment"]
D --> E{"生效日晚於到期日?"}
E -- 是 --> X1["400 AUTH_400012"]
E -- 否 --> F{"同人同角色同範圍期間重疊?"}
F -- 是 --> X2["409 AUTH_409018"]
F -- 否 --> G{"是該租戶成員?"}
G -- 否 --> X3["400 AUTH_400014"]
G -- 是 --> OK["已建立 N 筆指派<br/>部分失敗時列出失敗的人"]
UC-ASSIGN-02 編輯期間或移除¶
| 項目 | 內容 |
|---|---|
| 角色 | 持 iam.user.assign |
| 前置條件 | 不會讓原廠租戶最後一位系統管理員失去有效指派 |
| 產出後置 | 更新起訖或刪除該筆 |
改完或刪完後,該人「現在仍有效」的指派要留得住原廠管理員身分,否則擋下——過期、未生效、角色停用的列不算數,避免留一筆過期指派或把唯一那筆改成過去期間來繞過保護。
3. 權限矩陣¶
| 操作 | FE 判定 | BE 強制 | BE 檢查位置 |
|---|---|---|---|
| 進入、列表 | 側欄可見=iam.user.read(ALL);頁面 v-can 同一項 |
iam.user.read |
jedi-iam role_assignment_route.py(RoleAssignmentsRoute) |
| 新增 | v-can iam.user.assign |
iam.user.assign |
RoleAssignmentCreateRoute |
| 編輯、移除 | v-can iam.user.assign(整欄隱藏) |
iam.user.assign |
RoleAssignmentRoute.put/delete |
| 檢查存取 | 同進入 | 查他人需 iam.user.read;查自己放行 |
UserEffectiveAccessRoute |
4. 狀態機與前置條件¶
指派狀態(前端依日期推,useRoleAssignmentList.js assignmentStatus):
| 狀態 | 條件 | 判定採計 |
|---|---|---|
| 未生效 | starts_at 在未來 |
否 |
| 有效 | 期間內且角色、帳號都啟用 | 是 |
| 停用 | 期間內但角色或帳號已停用(is_active=false) |
否 |
| 已到期 | ends_at 已過 |
否;表上預設隱藏,開「顯示已到期」才出現 |
期間:生效日選今天=立即生效;指定日期=當天 00:00 起。到期日=當天 23:59:59 結束;不填=永久。
生效時機:權限判定每次請求依當下有效指派計算,到期即不再放行;側欄選單與登入憑證內的管理員旗標在重新登入後更新。
| 條件 | 效果 | 出處 |
|---|---|---|
| 生效晚於到期 | 400 AUTH_400012 |
role_assignment_service.py(_assert_period) |
| 同人、同角色、同範圍期間重疊 | 409 AUTH_409018 |
_assert_no_overlap |
| 被指派者不是該租戶成員 | 400 AUTH_400014 |
_resolve_scope |
| 角色不屬於該租戶、範圍不正確 | 400 AUTH_400013 |
_resolve_scope/_assert_role_usable_in |
| 會讓原廠管理員失去最後一筆有效指派 | 403 | _assert_root_admin_keeps_role |
| 指派不存在 | 404 AUTH_404008 |
5. UI 設計¶
頁首(標題、說明、「新增指派」)→ 檢查存取搜尋框 → 未搜尋時:工具列(依人/依角色、角色篩選、僅檢視某人標籤、顯示已到期)+分組 DataTable+表尾總數;搜尋某人後整塊換成 檢查存取 結果。新增/編輯指派為對話框(虛線層),編輯時無預覽、角色唯讀。
📸 實機截圖待補(亮色模式):依人分組、依角色分組、新增指派對話框(含預覽)、已到期顯示。
6. API 規格¶
6.1 總清單¶
| 分類 | Method + Path | 說明 | 守門 |
|---|---|---|---|
| 列表 | POST /api/1.0/role-assignments |
分頁+篩選 | iam.user.read |
| 新增 | POST /api/1.0/role-assignment |
一次一人 | iam.user.assign |
| 編輯 | PUT /api/1.0/role-assignment/<id> |
只改期間 | iam.user.assign |
| 移除 | DELETE /api/1.0/role-assignment/<id> |
iam.user.assign |
|
| 檢查存取 | GET /api/1.0/users/<uid>/effective-access |
見 檢查存取 | 查他人 iam.user.read |
| 下拉 | GET /api/1.0/roles/menu/GET /api/1.0/users/menu |
角色/人 | iam.role.read/登入即可 |
| 預覽 | POST /api/1.0/ui-routes/visible-by-capabilities |
新增對話框預覽 | iam.role.read |
6.2 列表¶
Request:
{
"pager": {"page": 1, "page_size": 25, "with_total": true},
"sort": [{"field": "user_id", "order": "asc"}, {"field": "starts_at", "order": "asc"}],
"filters": {"role_uid": null, "user_uid": null, "hide_expired": true}
}
篩選另可帶 org_unit_id、active_only。回應每列(RoleAssignmentResponse):
| 欄位 | 型別 | 說明 |
|---|---|---|
id |
int | 指派 id |
user_uid / user_login_name / user_nickname |
string | |
role_uid / role_name |
string | |
scope |
string | tenant/org_unit |
tenant_id / org_unit_id / org_unit_name |
範圍 | |
starts_at / ends_at |
datetime | ends_at 空=永久 |
is_active |
bool | 期間內且角色、帳號皆啟用 |
is_default |
bool | 資料欄位保留,畫面不顯示 |
出處:jedi-iam api/serializers/role_assignment.py。
6.3 新增/編輯¶
{
"user_uid": "…",
"role_uid": "…",
"scope": "tenant",
"tenant_id": 102,
"starts_at": "2026-10-08 00:00:00",
"ends_at": "2026-12-31 23:59:59"
}
tenant_id 帶被指派者所屬租戶;不帶時後端用操作者當下租戶(指派子租戶的人會被擋)。編輯只收 scope、starts_at、ends_at。
7. 前端檔案地圖(compliance-manager-fe/)¶
| 檔案 | 角色 |
|---|---|
src/views/access/AssignmentManage.vue |
頁面本體 |
src/views/access/AssignmentDialog.vue |
新增/編輯對話框(帳號頁、角色明細共用) |
src/views/access/AssignmentFormBody.vue、AssignmentMenuPreview.vue、assignmentPeriod.js |
角色+期間表單、預覽、期間換算 |
src/views/access/CheckAccessBar.vue、EffectiveAccessView.vue |
檢查存取 |
src/composables/useRoleAssignmentList.js |
列表與狀態推算 |
src/service/RoleAssignmentService.js |
API |
8. 後端檔案地圖¶
| 鏈路 | Route | Service | 底層 |
|---|---|---|---|
| 指派 CRUD | jedi-iam api/routes/role_assignment_route.py |
jedi-iam app/service/role_assignment_service.py |
user_role repo;原廠管理員保護由宿主 root admin guard 判 |
9. DB¶
| 表 | 讀寫 | 說明 |
|---|---|---|
public.user_roles |
讀/寫 | 指派本體 |
public.roles、public.users、public.user_tenants |
讀 | 角色、人、租戶成員檢查 |
public.user_roles
| 欄位 | 型別 | 說明 |
|---|---|---|
id |
bigint | |
user_id / role_id |
integer | |
scope |
varchar | tenant/org_unit |
tenant_id / org_unit_id |
integer | 範圍 |
starts_at / ends_at |
timestamptz | 有效期間;ends_at 空=永久 |
is_default |
boolean | 保留,判定與畫面不使用 |
10. 頁面邏輯與資料對應¶
列表依分組欄先排序再分頁(分組列才會連續);「顯示已到期」關閉時另數一次總數,算出隱藏筆數。網址參數 role_uid(角色篩選)、user_uid(只看某人)、check(檢查存取對象)可直接分享。
11. 背景行為與外部依賴¶
| 類型 | 內容 |
|---|---|
| 排程 | 無——到期由判定當下比對日期,不需要排程清除 |
| 通知 | 無 |
| 套件 | jedi-iam |
12. 邊界情況與已知坑¶
- 一次只能指派同一租戶的人:角色屬於租戶,跨租戶多選時提示並擋下。
- 編輯不能換人換角色:要換請移除後重建(後端不收)。
- 部門範圍目前等同整租戶:API 收
scope=org_unit並記下部門,但判定不看部門;畫面不送部門。 - 移除後要重新登入側欄才更新:API 判定立即生效,側欄選單與登入憑證內的管理員旗標在重新登入後才更新。