Keycloak 中的 RBAC 和細微管理員權限 V2 模型
1.Keycloak中的角色概述
Keycloak 中的角色是分散存取的主要機制。應用程式檢查使用者的角色(透過令牌中的聲明)來決定允許使用者執行哪些操作。 Keycloak supports two types of roles:領域角色和客戶角色.
領域角色與客戶端角色
| 特徵 | 領域角色 | 客戶角色 |
|---|---|---|
| 範圍 | 整個領域 | 僅針對特定客戶 |
| 使用案例 | 一般角色(管理員、使用者、經理) | 應用程式特定角色(編輯者、檢視者) |
| 命名空間 | 領域獨一無二 | 在客戶端獨一無二 |
| 代幣領取 | 領域訪問角色 | resources_access.{client}.roles |
2. 領域角色
2.1 預設領域角色
Keycloak 提供了許多領域角色:
預設角色-{領域}— 複合角色包含新使用者的預設角色
離線訪問— 允許取得離線令牌(長期令牌刷新)
uma_授權— 允許使用 UMA(使用者管理存取)
2.2 創建領域角色
透過管理控制台:
點選領域角色在側邊欄中
點選創建角色
進入:
- 角色名稱:
行政。行政 - 描述:
完全管理員存取權限
- 角色名稱:
點選節省
透過管理 CLI:
# Tạo realm roles bin/kcadm.sh create roles -r my-company -s name=admin -s description="Full administrator access" bin/kcadm.sh create roles -r my-company -s name=manager -s description="Manager with limited admin access" bin/kcadm.sh create roles -r my-company -s name=user -s description="Regular user" bin/kcadm.sh create roles -r my-company -s name=viewer -s description="Read-only access"Xem danh sách realm roles
bin/kcadm.sh get roles -r my-company --fields name,description
透過 REST API:
# Tạo realm role curl -s -X POST \ "http://localhost:8080/admin/realms/my-company/roles" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "admin", "description": "Full administrator access", "composite": false }'Lấy danh sách realm roles
curl -s -X GET
"http://localhost:8080/admin/realms/my-company/roles"
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[].name'
3. 客戶角色
當應用程式需要自己的角色時,使用客戶端角色 - 例如,CMS 應用程式具有角色編輯, 作者, 審稿人與HR應用程式的角色不同。
3.1 建立客戶端角色
透過管理控制台:
進入客戶→ 選擇客戶端(例如:
我的網頁應用程式)選項卡角色
點選創建角色
輸入名稱和描述
透過 CLI:
# Lấy client ID CLIENT_UUID=$(bin/kcadm.sh get clients -r my-company -q clientId=my-web-app --fields id --format csv --noquotes)Tạo client roles
bin/kcadm.sh create clients/$CLIENT_UUID/roles -r my-company
-s name=editor -s description="Can create and edit content"bin/kcadm.sh create clients/$CLIENT_UUID/roles -r my-company
-s name=author -s description="Can create content"bin/kcadm.sh create clients/$CLIENT_UUID/roles -r my-company
-s name=reviewer -s description="Can review and approve content"bin/kcadm.sh create clients/$CLIENT_UUID/roles -r my-company
-s name=content-admin -s description="Full content management"Xem client roles
bin/kcadm.sh get clients/$CLIENT_UUID/roles -r my-company --fields name,description
透過 REST API:
curl -s -X POST \
"http://localhost:8080/admin/realms/my-company/clients/$CLIENT_UUID/roles" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "editor",
"description": "Can create and edit content"
}'
3.2 Token 中的客戶端角色
客戶端角色出現在宣告下的存取權杖中資源訪問:
{
"realm_access": {
"roles": ["user", "offline_access"]
},
"resource_access": {
"my-web-app": {
"roles": ["editor", "author"]
},
"my-api": {
"roles": ["read", "write"]
},
"account": {
"roles": ["manage-account", "view-profile"]
}
}
}
4. 複合角色
複合角色是包含一個或多個子角色(領域角色和/或客戶端角色)的角色。當為使用者指派複合角色時,該使用者自動擁有所有子角色。
4.1 創建複合角色
透過管理控制台:
進入領域角色→ 選擇角色(例如:
行政。行政)選項卡行動 → 新增關聯角色
選擇要新增的角色(領域角色和/或客戶端角色)
點選分配
透過 CLI:
# Tạo composite role: "manager" chứa "user" và "viewer" bin/kcadm.sh add-roles \ -r my-company \ --rname manager \ --rolename user \ --rolename viewerThêm client roles vào composite role
bin/kcadm.sh add-roles
-r my-company
--rname manager
--cclientid my-web-app
--rolename editor
--rolename reviewer
層次結構範例:
admin (composite)
├── manager (composite)
│ ├── user (realm role)
│ ├── viewer (realm role)
│ ├── my-web-app/editor (client role)
│ └── my-web-app/reviewer (client role)
├── my-web-app/content-admin (client role)
└── account/manage-account (client role)
筆記:當使用者被指派角色時行政。行政,用戶將會擁有它全部樹層次結構中的角色:行政。行政, 主管, 用戶.用戶, 觀眾。觀眾, 編輯, 審稿人, 內容管理, 管理帳號.
4.2 查看複合角色
# Xem roles con của composite role bin/kcadm.sh get-roles -r my-company --rname admin --effectiveREST API
curl -s -X GET
"http://localhost:8080/admin/realms/my-company/roles/admin/composites"
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[].name'
5. 角色映射
5.1 為使用者分配角色
透過管理控制台:
進入使用者→ 選擇用戶
選項卡角色映射
點選分配角色
選擇領域角色或按客戶端過濾以選擇客戶端角色
點選分配
透過 CLI:
# Gán realm roles cho user bin/kcadm.sh add-roles \ -r my-company \ --uusername john.doe \ --rolename adminGán client roles cho user
bin/kcadm.sh add-roles
-r my-company
--uusername john.doe
--cclientid my-web-app
--rolename editorXem roles của user (bao gồm effective roles từ composite và groups)
bin/kcadm.sh get-roles
-r my-company
--uusername john.doe
--effective
透過 REST API:
# Lấy role representation ROLE_ID=$(curl -s -X GET \ "http://localhost:8080/admin/realms/my-company/roles/admin" \ -H "Authorization: Bearer $ACCESS_TOKEN" | jq -r '.id')ROLE_NAME=$(curl -s -X GET
"http://localhost:8080/admin/realms/my-company/roles/admin"
-H "Authorization: Bearer $ACCESS_TOKEN" | jq -r '.name')Gán realm role cho user
curl -s -X POST
"http://localhost:8080/admin/realms/my-company/users/$USER_ID/role-mappings/realm"
-H "Authorization: Bearer $ACCESS_TOKEN"
-H "Content-Type: application/json"
-d "[$(curl -s -X GET
"http://localhost:8080/admin/realms/my-company/roles/admin"
-H "Authorization: Bearer $ACCESS_TOKEN")]"
5.2 將角色分配給群組
在為群組指派角色時,所有成員該群組(和子群組)的成員將繼承該角色:
# Qua CLI
bin/kcadm.sh add-roles \
-r my-company \
--gname Engineering \
--rolename user
bin/kcadm.sh add-roles \
-r my-company \
--gname Engineering \
--cclientid my-web-app \
--rolename viewer
# Qua REST API
curl -s -X POST \
"http://localhost:8080/admin/realms/my-company/groups/$GROUP_ID/role-mappings/realm" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "[$(curl -s -X GET \
"http://localhost:8080/admin/realms/my-company/roles/user" \
-H "Authorization: Bearer $ACCESS_TOKEN")]"
5.3 有效角色
使用者的有效角色=直接指派的角色+從群組繼承的角色+複合角色的角色:
# Xem effective realm roles curl -s -X GET \ "http://localhost:8080/admin/realms/my-company/users/$USER_ID/role-mappings/realm/composite" \ -H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[].name'Xem effective client roles
curl -s -X GET
"http://localhost:8080/admin/realms/my-company/users/$USER_ID/role-mappings/clients/$CLIENT_UUID/composite"
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[].name'
6. 預設角色
建立帳戶或註冊時,預設角色會自動指派給每個新使用者。
6.1 配置預設角色
透過管理控制台:
進入領域角色
尋找角色預設角色-{領域}(例如:
預設角色我的公司)點選角色 → 選項卡行動 → 新增關聯角色
選擇您要設定為預設的角色
透過 CLI:
# Thêm role vào default roles bin/kcadm.sh add-roles \ -r my-company \ --rname default-roles-my-company \ --rolename user \ --rolename offline_accessThêm client role vào default roles
bin/kcadm.sh add-roles
-r my-company
--rname default-roles-my-company
--cclientid my-web-app
--rolename viewer
之後,每個新建立的使用者將自動擁有角色:用戶.用戶, 離線訪問, 我的網頁應用程式/檢視器.
7. 服務帳號角色
服務帳戶用於服務之間的通訊(機器對機器)-無需使用者互動。
7.1 為客戶端啟用服務帳戶
進入客戶→ 選擇或建立客戶
選項卡設定:
- 客戶端認證: 在
- 服務帳號角色: 在
- 授權:關閉(除非需要授權服務)
點選節省
7.2 為服務帳戶分配角色
# Qua Admin Console: # Clients → chọn client → tab "Service account roles" → Assign roleQua CLI - lấy service account user
SA_USER_ID=$(bin/kcadm.sh get clients/$CLIENT_UUID/service-account-user -r my-company --fields id --format csv --noquotes)
Gán realm roles
bin/kcadm.sh add-roles
-r my-company
--uid $SA_USER_ID
--rolename adminGán client roles (realm-management) cho API access
bin/kcadm.sh add-roles
-r my-company
--uid $SA_USER_ID
--cclientid realm-management
--rolename manage-users
--rolename view-users
--rolename manage-clients
7.3 使用服務帳戶
# Lấy access token cho service account (client credentials grant) ACCESS_TOKEN=$(curl -s -X POST \ "http://localhost:8080/realms/my-company/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=my-backend-service" \ -d "client_secret=YOUR_CLIENT_SECRET" | jq -r '.access_token')Sử dụng token để gọi API
curl -s -X GET
"http://localhost:8080/admin/realms/my-company/users"
-H "Authorization: Bearer $ACCESS_TOKEN" | jq '.[].username'
8.細粒度管理者權限V2
細粒度的管理權限 V2(來自 Keycloak 26+)允許對誰可以管理管理控制台中的資源進行精細控制,而不僅僅是使用原始領域管理客戶端角色。
8.1 啟用細粒度管理權限
進入領域設定 → 一般的
尋找管理員權限→ 打開細粒度管理員權限(V2)
Keycloak會在realm中建立權限管理資源
筆記:這是 Keycloak 26.x 中的預覽功能。生產中,開機前需仔細評估。
8.2 資源權限
啟用後,您可以為資源建立權限:
使用者權限:
| 允許 | 描述 |
|---|---|
| 看法。看法 | 查看用戶列表和詳細信息 |
| 管理 | 建立、編輯、刪除用戶 |
| 地圖角色 | 為使用者指派/刪除角色 |
| 管理群組成員資格 | 在群組中新增/刪除用戶 |
| 模仿 | 冒充用戶 |
群組權限:
| 允許 | 描述 |
|---|---|
| 看法。看法 | 查看群組 |
| 管理 | 建立、編輯、刪除群組 |
| 查看會員 | 查看群組成員 |
| 管理成員 | 新增/刪除成員 |
| 管理會員資格 | 管理群組成員資格 |
客戶權限:
| 允許 | 描述 |
|---|---|
| 看法。看法 | 查看客戶 |
| 管理 | 建立、編輯、刪除客戶 |
| 配置 | 更改客戶端設定 |
| 地圖角色 | 創建/分配客戶角色 |
角色權限:
| 允許 | 描述 |
|---|---|
| 看法。看法 | 查看角色 |
| 管理 | 建立、編輯、刪除角色 |
| 地圖角色 | 將角色指派給使用者/群組 |
8.3 建立權限
進入領域設定 → 管理員權限
選擇資源類型(使用者、群組、客戶端、角色)
點選需要配置的權限(例如:管理對於用戶)
更多的政策。政策確定誰擁有此權限
8.4 政策
策略定義授予權限的條件。 Keycloak V2支援以下策略:
基於角色的策略:
// Cho phép users có role "hr-admin" quản lý users
{
"type": "role",
"name": "HR Admin Policy",
"description": "Users with hr-admin role",
"roles": [
{
"id": "{role-id-of-hr-admin}",
"required": true
}
]
}
基於使用者的政策:
// Cho phép specific users
{
"type": "user",
"name": "Specific Admin Policy",
"users": [
"{user-id-of-admin-1}",
"{user-id-of-admin-2}"
]
}
基於團體的政策:
// Cho phép members của group
{
"type": "group",
"name": "Admin Group Policy",
"groups": [
{
"id": "{group-id-of-admins}",
"extendChildren": true
}
]
}
基於客戶的政策:
// Cho phép specific clients (service accounts)
{
"type": "client",
"name": "Backend Service Policy",
"clients": [
"{client-id-of-backend-service}"
]
}
8.5 實際範例:HR Admin 只管理用戶
要求:使用者有角色人力資源管理員只允許查看和管理用戶,不允許管理客戶端或領域設定。
創建領域角色
人力資源管理員:bin/kcadm.sh create roles -r my-company \ -s name=hr-admin \ -s description="HR Administrator - can manage users only"啟用細粒度管理員權限V2
創建基於角色的策略給
人力資源管理員:- 前往管理員權限 → 策略選項卡
- 建立策略 → 基於角色
- 名稱:《人力資源管理政策》
- 選擇角色:
人力資源管理員
將策略指派給使用者權限:
- 使用者→權限看法。看法→ 新增策略“HR 管理策略”
- 使用者→權限管理→ 新增策略“HR 管理策略”
為使用者指派角色:
bin/kcadm.sh add-roles -r my-company \ --uusername hr-manager \ --rolename hr-admin
現在用戶人力資源經理可以登入管理控制台並且只能看到選單使用者.
8.6 權限評估
您可以使用“評估”選項卡測試權限:
進入管理員權限 → 評價
選擇要測試的使用者或客戶端
選擇資源類型和權限
點選評價查看結果(允許或拒絕)
9. 專用領域管理控制台
Keycloak 允許為每個領域建立單獨的管理員帳戶 - 無需存取主領域:
9.1 建立領域管理員
# Tạo user trong realm bin/kcadm.sh create users -r my-company \ -s username=realm-admin \ -s [email protected] \ -s enabled=true \ -s emailVerified=truebin/kcadm.sh set-password -r my-company
--username realm-admin
--new-password "RealmAdmin@123"Gán realm-management client roles
bin/kcadm.sh add-roles -r my-company
--uusername realm-admin
--cclientid realm-management
--rolename realm-admin
9.2 領域管理客戶端角色
客戶領域管理控制管理員權限的可用角色:
| 角色 | 描述 |
|---|---|
| 領域管理 | 領域的完全管理員存取權限 |
| 管理用戶 | 管理用戶 |
| 查看用戶 | 查看用戶 |
| 管理客戶 | 管理客戶 |
| 查看客戶 | 查看客戶 |
| 管理領域 | 管理領域設定 |
| 視界 | 查看領域設置 |
| 管理身分提供者 | 管理身分提供者 |
| 管理事件 | 管理活動 |
| 管理授權 | 授權管理 |
| 冒充 | 冒充用戶 |
| 查詢用戶 | 搜尋用戶 |
| 查詢群組 | 搜尋群組 |
| 查詢客戶端 | 尋找客戶 |
| 查詢領域 | 搜尋領域 |
例如:建立一個僅管理使用者和群組的受限管理員:
bin/kcadm.sh add-roles -r my-company \
--uusername limited-admin \
--cclientid realm-management \
--rolename manage-users \
--rolename view-users \
--rolename query-users \
--rolename query-groups
10. 在應用程式中使用角色
10.1 從訪問令牌檢查角色
解碼後的存取權杖包含角色:
{
"sub": "user-uuid",
"realm_access": {
"roles": [
"admin",
"manager",
"user",
"default-roles-my-company",
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"my-web-app": {
"roles": [
"editor",
"content-admin"
]
},
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
}
}
10.2 Spring引導範例
// SecurityConfig.java @Configuration @EnableWebSecurity public class SecurityConfig {@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/api/admin/**").hasRole("admin") .requestMatchers("/api/content/**").hasRole("editor") .requestMatchers("/api/public/**").permitAll() .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .jwtAuthenticationConverter(jwtAuthenticationConverter()) ) ); return http.build(); } @Bean public JwtAuthenticationConverter jwtAuthenticationConverter() { JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter(); converter.setAuthoritiesClaimName("realm_access.roles"); converter.setAuthorityPrefix("ROLE_"); JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter(); jwtConverter.setJwtGrantedAuthoritiesConverter(converter); return jwtConverter; }
}
10.3 Node.js (Express) 中的範例
// middleware/auth.js const jwt = require('jsonwebtoken');function hasRealmRole(role) { return (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'No token provided' });
try { const decoded = jwt.decode(token); const roles = decoded.realm_access?.roles || []; if (roles.includes(role)) { req.user = decoded; next(); } else { res.status(403).json({ error: 'Insufficient permissions' }); } } catch (err) { res.status(401).json({ error: 'Invalid token' }); }}; }
function hasClientRole(clientId, role) { return (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'No token provided' });
try { const decoded = jwt.decode(token); const roles = decoded.resource_access?.[clientId]?.roles || []; if (roles.includes(role)) { req.user = decoded; next(); } else { res.status(403).json({ error: 'Insufficient permissions' }); } } catch (err) { res.status(401).json({ error: 'Invalid token' }); }}; }
// Sử dụng app.get('/api/admin/users', hasRealmRole('admin'), (req, res) => { // Only admin can access });
app.post('/api/content', hasClientRole('my-web-app', 'editor'), (req, res) => { // Only editors can create content });
11.練習練習
創建領域角色:
超管理員,主管,職員,觀眾。觀眾創建客戶角色為客戶
我的網頁應用程式:內容編輯器,內容審閱者,內容發佈者創建複合角色:
超管理員包含:主管+ 所有客戶角色主管包含:職員+內容審閱者職員包含:觀眾。觀眾+內容編輯器
將角色指派給群組:
- 團體
工程: 領域角色職員 - 團體
工程/後端:客戶角色內容編輯器
- 團體
啟用細粒度管理員權限V2並創建:
- 基於角色的策略
人力資源管理員 - 將策略指派給使用者檢視/管理權限
- 使用具有角色的使用者進行測試
人力資源管理員
- 基於角色的策略
建立服務帳戶為客戶
我的後端服務有角色管理用戶,查看用戶並使用客戶端憑證授予進行測試
12. 總結
在本課中,您學習了:
區分領域角色和客戶角色
創造複合角色具有分散的層次結構
角色映射對於使用者和群組(直接和舊)
配置預設角色對於新用戶
使用服務帳號角色用於機器對機器通信
細粒度管理員權限V2具有策略(基於角色、基於使用者、基於群組、基於客戶端)
創造專用領域管理員具有有限的權限
檢查應用程式中的角色(Spring Boot、Node.js)
下一篇文章將提供說明客戶端、客戶端範圍和 OpenID Connect在鑰匙斗篷裡。