🎯 權限管理組件執行流程詳解
🏗? 組件架構圖
┌─────────────────────────────────────────────────────────────┐
│ HTTP請求 │
└─────────────────────┬───────────────────────────────────────┘│
┌─────────────────────▼───────────────────────────────────────┐
│ SecureController │
│ - 獲取當前用戶ID │
│ - 統一錯誤處理 │
└─────────────────────┬───────────────────────────────────────┘│
┌─────────────────────▼───────────────────────────────────────┐
│ SecurityService (接口) │
│ - 業務語義化的權限檢查方法 │
│ - canAccessUser(), canCreateProcurement()等 │
└─────────────────────┬───────────────────────────────────────┘│
┌─────────────────────▼───────────────────────────────────────┐
│ SecurityServiceImpl (實現) │
│ - 構建SecurityContext │
│ - 調用PermissionEngine │
│ - 異常處理 │
└─────────────────────┬───────────────────────────────────────┘│
┌─────────────────────▼───────────────────────────────────────┐
│ PermissionEngine (接口) │
│ - 權限計算的抽象接口 │
│ - checkPermission()方法 │
└─────────────────────┬───────────────────────────────────────┘│
┌─────────────────────▼───────────────────────────────────────┐
│ RoleBasedPermissionEngine (實現) │
│ - 具體的權限計算邏輯 │
│ - 基于角色的權限規則 │
└─────────────────────────────────────────────────────────────┘
🔄 完整執行流程
場景:BUYER用戶想查看自己的信息
讓我們跟蹤一個完整的請求:GET /api/v1/users/123
第1步:SecureController - 安全控制器基類
// 任何繼承SecureController的Controller
@RestController
class UserController(currentUserService: CurrentUserService,private val securityService: SecurityService // 👈 注入SecurityService接口
) : SecureController(currentUserService) {@GetMapping("/api/v1/users/{userId}")fun getUserInfo(@PathVariable userId: String): ResponseEntity<UserInfo> {// 1.1 獲取當前用戶ID(來自SecureController基類)val currentUserId = getCurrentUserId() // 返回 "123"// 1.2 調用SecurityService進行權限檢查if (!securityService.canAccessUser(userId)) { // 👈 調用接口方法return createForbiddenResponse()}// 1.3 執行業務邏輯val userInfo = userService.getUserInfo(userId)return ResponseEntity.ok(userInfo)}
}
SecureController說:“我獲取到當前用戶ID是123,現在要檢查是否可以訪問用戶123的信息,讓我問問SecurityService!”
第2步:SecurityService - 權限服務接口
// SecurityService.kt - 接口定義
interface SecurityService {/*** 是否可以訪問用戶信息*/fun canAccessUser(userId: String?): Boolean // 👈 業務語義化的方法/*** 是否可以創建采購需求*/fun canCreateProcurement(): Boolean// ... 其他業務權限方法
}
SecurityService接口說:“我定義了所有業務權限檢查的方法,具體實現由SecurityServiceImpl來完成!”
第3步:SecurityServiceImpl - 權限服務實現
// SecurityServiceImpl.kt - 具體實現
@Service("securityService")
class SecurityServiceImpl(private val currentUserService: CurrentUserService,private val permissionEngine: PermissionEngine // 👈 注入PermissionEngine接口
) : SecurityService {override fun canAccessUser(userId: String?): Boolean {// 3.1 調用通用權限檢查方法return safeCheckPermission("user", "read", userId) // 👈 轉換為通用格式}private fun safeCheckPermission(resource: String, // "user"action: String, // "read"targetId: String? // "123"): Boolean {return try {// 3.2 構建安全上下文val context = getCurrentSecurityContext() ?: return false// 3.3 調用權限引擎進行具體檢查permissionEngine.checkPermission(context, resource, action, targetId) // 👈 委托給引擎} catch (e: Exception) {false // 異常時拒絕訪問}}private fun getCurrentSecurityContext(): SecurityContext? {return try {val currentUserResult = currentUserService.getCurrentUser()if (!currentUserResult.isSuccess) return nullval currentUser = currentUserResult.data!!val role = Role.fromCode(currentUser.role.name) ?: return null// 3.4 創建SecurityContext對象SecurityContext(userId = currentUser.id.value.toString(), // "123"userRole = role, // Role.BUYERuserStatus = currentUser.status.name // "ACTIVE")} catch (e: Exception) {null}}
}
SecurityServiceImpl說:“我收到canAccessUser請求,讓我構建安全上下文,然后調用權限引擎來做具體判斷!”
第4步:PermissionEngine - 權限引擎接口
// PermissionEngine.kt - 權限計算引擎接口
interface PermissionEngine {/*** 檢查權限*/fun checkPermission(context: SecurityContext, // 安全上下文resource: String, // 資源類型action: String, // 操作類型targetId: String? = null // 目標ID): Booleanfun getEngineVersion(): Stringfun getEngineDescription(): String
}
PermissionEngine接口說:“我定義了權限計算的標準接口,具體的計算邏輯由不同的實現來完成!”
第5步:RoleBasedPermissionEngine - 基于角色的權限引擎
// RoleBasedPermissionEngine.kt - 具體的權限計算實現
@Component
class RoleBasedPermissionEngine : PermissionEngine {override fun checkPermission(context: SecurityContext, // userId="123", userRole=BUYER, userStatus="ACTIVE"resource: String, // "user"action: String, // "read"targetId: String? // "123"): Boolean {// 5.1 基礎檢查:非活躍用戶無權限if (!context.isActive()) {return false}// 5.2 管理員檢查:管理員擁有所有權限if (context.isAdmin()) {return true}// 5.3 根據角色進行具體權限檢查return when (context.userRole) {Role.BUYER -> checkBuyerPermission(context, resource, action, targetId) // 👈 BUYER角色Role.SELLER -> checkSellerPermission(context, resource, action, targetId)Role.FORWARDER -> checkForwarderPermission(context, resource, action, targetId)Role.SALES -> checkSalesPermission(context, resource, action, targetId)Role.SUPPORT -> checkSupportPermission(context, resource, action, targetId)Role.ADMIN -> true // 已在上面處理}}private fun checkBuyerPermission(context: SecurityContext, // userId="123", userRole=BUYERresource: String, // "user"action: String, // "read"targetId: String? // "123"): Boolean {return when (resource) {"user" -> when (action) {"read" -> context.canAccessUserData(targetId) // 👈 檢查是否可以訪問用戶數據"write" -> context.canAccessUserData(targetId)else -> false}"procurement" -> when (action) {"create" -> true // BUYER可以創建采購需求"read" -> true // BUYER可以查看采購需求"write" -> canAccessOwnResource(context, targetId) // 只能修改自己的else -> false}// ... 其他資源else -> false}}
}
RoleBasedPermissionEngine說:“讓我分析…用戶123是BUYER角色,想讀取用戶123的信息,這是訪問自己的數據,允許!”
🎭 各組件的具體職責
1. SecureController(安全控制器基類)
// 職責:提供安全基礎設施
abstract class SecureController {protected fun getCurrentUserId(): String // 獲取當前用戶IDprotected fun resolveUserId(String?): String // 解析目標用戶IDprotected fun createForbiddenResponse(): ResponseEntity // 創建403響應
}
角色:安全基礎設施提供者
工作:獲取用戶身份、統一錯誤處理
2. SecurityService(權限服務接口)
// 職責:定義業務權限檢查接口
interface SecurityService {fun canAccessUser(userId: String?): Boolean // 業務語義化fun canCreateProcurement(): Boolean // 業務語義化fun canModifyOrder(orderId: String?): Boolean // 業務語義化
}
角色:業務權限接口定義者
工作:提供清晰的業務語義化權限檢查方法
3. SecurityServiceImpl(權限服務實現)
// 職責:協調和轉換
@Service
class SecurityServiceImpl {private fun safeCheckPermission(resource, action, targetId): Boolean // 轉換格式private fun getCurrentSecurityContext(): SecurityContext // 構建上下文
}
角色:協調者和轉換器
工作:
- 將業務方法轉換為通用權限檢查
- 構建SecurityContext
- 異常處理
- 委托給權限引擎
4. PermissionEngine(權限引擎接口)
// 職責:定義權限計算接口
interface PermissionEngine {fun checkPermission(context, resource, action, targetId): Boolean // 通用權限檢查
}
角色:權限計算接口定義者
工作:定義標準的權限計算接口,支持可插拔實現
5. RoleBasedPermissionEngine(基于角色的權限引擎)
// 職責:具體的權限計算邏輯
@Component
class RoleBasedPermissionEngine {private fun checkBuyerPermission(...): Boolean // BUYER角色權限private fun checkSellerPermission(...): Boolean // SELLER角色權限private fun checkAdminPermission(...): Boolean // ADMIN角色權限
}
角色:權限計算執行者
工作:
- 執行具體的權限計算邏輯
- 基于角色的權限規則
- 資源和操作的細粒度控制
🔄 數據流轉過程
// 數據在各組件間的流轉
HTTP請求: GET /api/v1/users/123↓
SecureController: getCurrentUserId() → "123"↓
SecurityService: canAccessUser("123")↓
SecurityServiceImpl: safeCheckPermission("user", "read", "123")↓
SecurityServiceImpl: getCurrentSecurityContext() → SecurityContext(userId="123", role=BUYER)↓
PermissionEngine: checkPermission(context, "user", "read", "123")↓
RoleBasedPermissionEngine: checkBuyerPermission(context, "user", "read", "123")↓
SecurityContext: canAccessUserData("123") → true (同一用戶)↓
返回結果: true → 允許訪問
🎯 為什么要這樣設計?
1. 單一職責原則
- SecureController:只負責安全基礎設施
- SecurityService:只負責業務權限接口
- SecurityServiceImpl:只負責協調和轉換
- PermissionEngine:只負責權限計算接口
- RoleBasedPermissionEngine:只負責具體權限邏輯
2. 開閉原則
// 可以輕松添加新的權限引擎實現
@Component
class RuleBasedPermissionEngine : PermissionEngine {// 基于規則的權限計算
}@Component
class DatabasePermissionEngine : PermissionEngine {// 基于數據庫配置的權限計算
}
3. 依賴倒置原則
// 高層模塊依賴抽象,不依賴具體實現
class SecurityServiceImpl(private val permissionEngine: PermissionEngine // 依賴接口,不是具體實現
)
4. 接口隔離原則
// 不同層次的接口,職責明確
interface SecurityService { // 業務層接口fun canAccessUser(String?): Boolean
}interface PermissionEngine { // 權限計算接口fun checkPermission(...): Boolean
}
🎊 總結
這5個組件形成了一個完整的權限管理體系:
- SecureController = 安全門衛:檢查身份,統一處理
- SecurityService = 業務顧問:提供業務語義化的權限檢查
- SecurityServiceImpl = 協調員:轉換格式,構建上下文,處理異常
- PermissionEngine = 權限計算標準:定義權限計算接口
- RoleBasedPermissionEngine = 權限計算器:執行具體的權限計算邏輯
就像一個完整的銀行業務流程:
- 門衛(SecureController):檢查身份證
- 業務顧問(SecurityService):了解業務需求
- 業務經理(SecurityServiceImpl):準備材料,協調各部門
- 審批標準(PermissionEngine):定義審批流程
- 審批員(RoleBasedPermissionEngine):根據規則做最終決定
這種設計讓權限管理既靈活又可維護! 🎉
ps:
好問題!讓我詳細解釋第4點和第5點的區別:
🤔 第4點和第5點的區別
📋 簡單對比
步驟 | 組件 | 職責 | 具體工作 |
---|---|---|---|
第4點 | SecurityService | 權限服務 | 調用權限引擎,但不做具體判斷 |
第5點 | RoleBasedPermissionEngine | 權限引擎 | 執行具體的權限計算邏輯 |
🔍 詳細解析
第4點:SecurityService - 權限服務(中介者)
// SecurityServiceImpl.kt
@Service
class SecurityServiceImpl : SecurityService {override fun canAccessUser(userId: String?): Boolean {// 👈 這里只是調用權限引擎,自己不做判斷return safeCheckPermission("user", "read", userId)}private fun safeCheckPermission(resource: String, action: String, targetId: String?): Boolean {return try {// 1. 獲取當前用戶的安全上下文val context = getCurrentSecurityContext() ?: return false// 2. 調用權限引擎進行檢查(重點:這里只是調用,不判斷)permissionEngine.checkPermission(context, resource, action, targetId)} catch (e: Exception) {false // 出錯就拒絕訪問}}
}
SecurityService說:“我收到了權限檢查請求,讓我準備好用戶信息,然后交給權限引擎去判斷!”
SecurityService的工作:
- 🔄 轉換參數:將業務參數轉換為權限引擎需要的格式
- 🛡? 異常處理:捕獲異常,確保系統安全
- 📋 獲取上下文:準備當前用戶的安全信息
- 📞 委托調用:把實際判斷工作交給權限引擎
第5點:RoleBasedPermissionEngine - 權限引擎(實際判斷者)
// RoleBasedPermissionEngine.kt
class RoleBasedPermissionEngine : PermissionEngine {override fun checkPermission(context: SecurityContext, // 用戶123,BUYER角色resource: String, // "user"action: String, // "read"targetId: String? // "123"): Boolean {// 👈 這里才是真正的權限判斷邏輯// 1. 非活躍用戶無權限if (!context.isActive()) return false// 2. 管理員擁有所有權限if (context.isAdmin()) return true// 3. 根據角色檢查權限return when (context.userRole) {Role.BUYER -> checkBuyerPermission(context, resource, action, targetId)// ... 其他角色}}private fun checkBuyerPermission(context: SecurityContext,resource: String,action: String,targetId: String?): Boolean {return when (resource) {"user" -> when (action) {"read" -> context.canAccessUserData(targetId) // 👈 具體的判斷邏輯else -> false}else -> false}}
}
RoleBasedPermissionEngine說:“讓我仔細分析…用戶123是BUYER角色,想讀取用戶123的信息,這是訪問自己的數據,允許!”
權限引擎的工作:
- 🧠 具體判斷:執行真正的權限計算邏輯
- 📊 角色分析:根據用戶角色決定權限范圍
- 🎯 資源檢查:判斷是否可以訪問特定資源
- ?? 規則執行:應用具體的業務權限規則
🎭 用生活例子來理解
SecurityService = 銀行前臺接待員
- 客戶:“我想查看我的賬戶信息”
- 接待員:“好的,讓我幫您準備資料,然后請權限部門審核”
- 接待員的工作:
- 收集客戶信息
- 準備審核材料
- 聯系權限部門
- 處理異常情況
RoleBasedPermissionEngine = 銀行權限審核部門
- 審核部門:“讓我看看…您是賬戶持有人,想查看自己的賬戶,符合規定,批準!”
- 審核部門的工作:
- 分析客戶身份
- 檢查權限規則
- 做出最終決定
- 返回審核結果
🔄 完整的調用鏈
// 完整的調用過程
Controller.getUserInfo(userId: "123")↓
SecurityService.canAccessUser("123") // 👈 第4點:準備和調用↓
SecurityService.safeCheckPermission("user", "read", "123")↓
RoleBasedPermissionEngine.checkPermission(context, "user", "read", "123") // 👈 第5點:具體判斷↓
RoleBasedPermissionEngine.checkBuyerPermission(...)↓
SecurityContext.canAccessUserData("123")↓
return true // 允許訪問
🎯 為什么要分成兩層?
1. 職責分離
// SecurityService:業務接口層
fun canAccessUser(userId: String?): Boolean // 業務語義清晰// PermissionEngine:權限計算層
fun checkPermission(context, resource, action, targetId): Boolean // 通用權限檢查
2. 異常處理
// SecurityService負責異常處理
private fun safeCheckPermission(...): Boolean {return try {permissionEngine.checkPermission(...) // 可能拋異常} catch (e: Exception) {false // 統一處理異常}
}
3. 擴展性
// 可以輕松替換權限引擎
class SecurityServiceImpl(private val permissionEngine: PermissionEngine // 可以是不同的實現
) {// RoleBasedPermissionEngine// RuleBasedPermissionEngine // DatabasePermissionEngine
}
4. 測試友好
// 可以單獨測試權限引擎
@Test
fun `BUYER角色應該可以訪問自己的數據`() {val context = SecurityContext(userId = "123", userRole = Role.BUYER)val result = permissionEngine.checkPermission(context, "user", "read", "123")assertTrue(result)
}
🎊 總結
第4點和第5點的核心區別:
方面 | SecurityService(第4點) | RoleBasedPermissionEngine(第5點) |
---|---|---|
角色 | 中介者、協調者 | 執行者、判斷者 |
職責 | 準備數據、調用引擎、處理異常 | 執行具體的權限計算邏輯 |
工作 | “我來幫你聯系權限部門” | “我來判斷你有沒有權限” |
復雜度 | 簡單的轉發和異常處理 | 復雜的業務規則和權限計算 |
可替換性 | 相對穩定 | 可以有多種實現(基于角色、基于規則等) |
就像餐廳點餐:
- SecurityService = 服務員:接收訂單,轉給廚房,處理問題
- RoleBasedPermissionEngine = 廚師:根據菜譜制作具體的菜品
兩者配合,形成了完整的權限檢查流程! 🎉