286 lines
9.2 KiB
Markdown
286 lines
9.2 KiB
Markdown
|
# Permission 權限管理模組 - Casbin 版
|
|||
|
|
|||
|
一個基於 **Casbin** 的現代化權限管理模組,完全整合你的專案技術棧,提供強大且靈活的 RBAC 權限控制。
|
|||
|
|
|||
|
## 🎯 為什麼選擇 Casbin?
|
|||
|
|
|||
|
你說得完全對!與其重新發明一個功能精簡的權限系統,**Casbin** 提供了:
|
|||
|
|
|||
|
### ✅ **社群驗證的成熟解決方案**
|
|||
|
- 🌟 **6.7k+ GitHub Stars**,經過大量生產環境驗證
|
|||
|
- 🔧 **功能完整**:支援 RBAC、ABAC、RESTful、通配符、正則表達式
|
|||
|
- 📚 **文檔完善**:豐富的範例和最佳實踐
|
|||
|
- 🛠️ **持續維護**:活躍的社群支持和定期更新
|
|||
|
|
|||
|
### ✅ **強大的功能特性**
|
|||
|
- **通配符支援**: `/api/users/*` 一個規則覆蓋所有子路徑
|
|||
|
- **正則表達式**: 靈活的權限匹配規則
|
|||
|
- **角色繼承**: 複雜的組織架構支援
|
|||
|
- **多種模型**: RBAC、ABAC、RESTful 等
|
|||
|
- **策略持久化**: 自動保存到你的 MongoDB
|
|||
|
|
|||
|
## 📁 目錄結構
|
|||
|
|
|||
|
```
|
|||
|
pkg/permission/
|
|||
|
├── config/ # Casbin 模型配置
|
|||
|
│ └── rbac_model.conf # RBAC 權限模型
|
|||
|
├── domain/ # 領域層
|
|||
|
│ ├── entity/ # 實體定義
|
|||
|
│ ├── repository/ # 倉庫介面
|
|||
|
│ ├── usecase/ # 用例介面 (Casbin 增強)
|
|||
|
│ └── config/ # 配置定義
|
|||
|
├── repository/ # 倉庫實現
|
|||
|
│ ├── casbin_adapter.go # Casbin MongoDB 適配器
|
|||
|
│ ├── client.go # 客戶端管理
|
|||
|
│ ├── role.go # 角色管理
|
|||
|
│ └── ... # 其他倉庫
|
|||
|
├── usecase/ # 用例實現 (Casbin API)
|
|||
|
├── svc/ # 初始化層
|
|||
|
├── example/ # Casbin 使用範例
|
|||
|
└── README.md # 本文件
|
|||
|
```
|
|||
|
|
|||
|
## 🚀 核心優勢
|
|||
|
|
|||
|
### **🔥 Casbin 強化功能**
|
|||
|
- **通配符權限**: `GET /api/users/*` 覆蓋所有用戶子路徑
|
|||
|
- **正則表達式**: `GET /api/users/\d+` 只允許數字 ID
|
|||
|
- **角色繼承**: `admin` 繼承 `user` 的所有權限
|
|||
|
- **策略分離**: 權限策略與業務邏輯完全分離
|
|||
|
- **動態更新**: 運行時動態添加/移除權限,無需重啟
|
|||
|
|
|||
|
### **⚡ 技術整合**
|
|||
|
- **MongoDB 適配器**: 策略自動持久化到你的 MongoDB
|
|||
|
- **你的錯誤系統**: 完整的 `@errs/` 整合
|
|||
|
- **緩存支援**: 使用你現有的 Redis 緩存
|
|||
|
- **go-zero 整合**: 無縫整合到你的服務架構
|
|||
|
|
|||
|
## 🔧 Casbin 模型
|
|||
|
|
|||
|
```ini
|
|||
|
# pkg/permission/config/rbac_model.conf
|
|||
|
[request_definition]
|
|||
|
r = sub, obj, act
|
|||
|
|
|||
|
[policy_definition]
|
|||
|
p = sub, obj, act
|
|||
|
|
|||
|
[role_definition]
|
|||
|
g = _, _
|
|||
|
|
|||
|
[policy_effect]
|
|||
|
e = some(where (p.eft == allow))
|
|||
|
|
|||
|
[matchers]
|
|||
|
m = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act)
|
|||
|
```
|
|||
|
|
|||
|
這個模型支援:
|
|||
|
- **keyMatch2**: 通配符匹配 (`/api/users/*`)
|
|||
|
- **regexMatch**: 正則表達式匹配
|
|||
|
- **角色繼承**: `g(user, role)` 關係
|
|||
|
|
|||
|
## 📦 快速整合
|
|||
|
|
|||
|
### 1. 在你的 ServiceContext 中添加
|
|||
|
|
|||
|
```go
|
|||
|
// internal/svc/service_context.go
|
|||
|
import "backend/pkg/permission/svc"
|
|||
|
|
|||
|
type ServiceContext struct {
|
|||
|
Config config.Config
|
|||
|
AuthMiddleware rest.Middleware
|
|||
|
AccountUC usecase.AccountUseCase
|
|||
|
PermissionUC permission.PermissionUseCase // ← Casbin 增強
|
|||
|
AuthUC permission.AuthUseCase
|
|||
|
RoleUC permission.RoleUseCase
|
|||
|
Validate vi.Validate
|
|||
|
}
|
|||
|
|
|||
|
func NewServiceContext(c config.Config) *ServiceContext {
|
|||
|
rds, err := redis.NewRedis(c.RedisConf)
|
|||
|
if err != nil {
|
|||
|
panic(err)
|
|||
|
}
|
|||
|
|
|||
|
return &ServiceContext{
|
|||
|
Config: c,
|
|||
|
AuthMiddleware: middleware.NewAuthMiddleware().Handle,
|
|||
|
AccountUC: NewAccountUC(&c, rds),
|
|||
|
PermissionUC: svc.NewPermissionUC(&c, rds), // ← Casbin 自動初始化
|
|||
|
AuthUC: svc.NewAuthUC(&c, rds),
|
|||
|
RoleUC: svc.NewRoleUC(&c),
|
|||
|
Validate: vi.MustValidator(),
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### 2. Casbin 強大功能使用
|
|||
|
|
|||
|
```go
|
|||
|
// 🔥 通配符權限 - 一個規則覆蓋所有子路徑
|
|||
|
err = permissionUC.AddPermissionForRole(ctx, "admin", "/api/users/*", ".*")
|
|||
|
|
|||
|
// ✅ 這些都會被允許:
|
|||
|
// GET /api/users/123
|
|||
|
// POST /api/users/123/profile
|
|||
|
// DELETE /api/users/123/avatar
|
|||
|
|
|||
|
// 🔥 正則表達式權限 - 精確控制
|
|||
|
err = permissionUC.AddPermissionForRole(ctx, "viewer", "/api/users/\\d+", "GET")
|
|||
|
|
|||
|
// ✅ 只允許: GET /api/users/123 (數字ID)
|
|||
|
// ❌ 拒絕: GET /api/users/abc (非數字ID)
|
|||
|
|
|||
|
// 🔥 角色繼承 - 組織架構支援
|
|||
|
err = permissionUC.AddRoleForUser(ctx, "john", "admin")
|
|||
|
err = permissionUC.AddRoleInheritance(ctx, "admin", "user")
|
|||
|
|
|||
|
// john 自動擁有 admin 和 user 的所有權限
|
|||
|
|
|||
|
// 🔥 動態權限檢查
|
|||
|
hasPermission, err := permissionUC.CheckUserPermission(ctx, "john", "GET", "/api/users/123")
|
|||
|
hasPattern, err := permissionUC.CheckPatternPermission(ctx, "john", "/api/users/456", "DELETE")
|
|||
|
```
|
|||
|
|
|||
|
## 🎯 實際使用場景
|
|||
|
|
|||
|
### **API 權限控制**
|
|||
|
```go
|
|||
|
// 中間件中使用
|
|||
|
func PermissionMiddleware(permissionUC permission.PermissionUseCase) rest.Middleware {
|
|||
|
return func(next http.HandlerFunc) http.HandlerFunc {
|
|||
|
return func(w http.ResponseWriter, r *http.Request) {
|
|||
|
userID := getUserIDFromJWT(r)
|
|||
|
|
|||
|
// Casbin 自動處理通配符和正則表達式
|
|||
|
hasPermission, err := permissionUC.CheckUserPermission(
|
|||
|
r.Context(), userID, r.Method, r.URL.Path,
|
|||
|
)
|
|||
|
|
|||
|
if err != nil || !hasPermission {
|
|||
|
httpx.WriteJsonCtx(r.Context(), w, 403, types.ErrorResp{
|
|||
|
Code: 4030001,
|
|||
|
Msg: "權限不足",
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
next(w, r)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### **權限初始化**
|
|||
|
```go
|
|||
|
// 初始化基礎權限
|
|||
|
func InitPermissions(ctx context.Context, permissionUC permission.PermissionUseCase) {
|
|||
|
// 🔥 管理員擁有所有 API 權限
|
|||
|
permissionUC.AddPermissionForRole(ctx, "admin", "/api/*", ".*")
|
|||
|
|
|||
|
// 🔥 用戶只能查看和更新自己的資料
|
|||
|
permissionUC.AddPermissionForRole(ctx, "user", "/api/users/{{.UserID}}", "GET|PUT")
|
|||
|
|
|||
|
// 🔥 訪客只能查看公開內容
|
|||
|
permissionUC.AddPermissionForRole(ctx, "guest", "/api/public/*", "GET")
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
## 📊 Casbin 策略儲存
|
|||
|
|
|||
|
### **MongoDB 自動持久化**
|
|||
|
```javascript
|
|||
|
// casbin_rules collection
|
|||
|
{
|
|||
|
_id: ObjectId,
|
|||
|
ptype: "p", // 策略類型
|
|||
|
v0: "role_admin_001", // 主體 (用戶/角色)
|
|||
|
v1: "/api/users/*", // 對象 (資源)
|
|||
|
v2: ".*", // 行為 (動作)
|
|||
|
v3: "", // 擴展字段
|
|||
|
v4: "", // 擴展字段
|
|||
|
v5: "" // 擴展字段
|
|||
|
}
|
|||
|
|
|||
|
// 角色關係
|
|||
|
{
|
|||
|
ptype: "g", // 分組策略
|
|||
|
v0: "user_001", // 用戶
|
|||
|
v1: "role_admin_001", // 角色
|
|||
|
v2: "",
|
|||
|
...
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
### **索引優化**
|
|||
|
```javascript
|
|||
|
// 自動創建的索引
|
|||
|
db.casbin_rules.createIndex({"ptype": 1})
|
|||
|
db.casbin_rules.createIndex({"ptype": 1, "v0": 1})
|
|||
|
db.casbin_rules.createIndex({"ptype": 1, "v0": 1, "v1": 1})
|
|||
|
```
|
|||
|
|
|||
|
## 🔥 Casbin vs 自建系統
|
|||
|
|
|||
|
| 功能 | 自建系統 | Casbin |
|
|||
|
|-----|---------|--------|
|
|||
|
| **通配符支援** | ❌ 需要自己實現 | ✅ 內建支援 `/api/users/*` |
|
|||
|
| **正則表達式** | ❌ 需要自己實現 | ✅ 內建支援 `/api/users/\\d+` |
|
|||
|
| **角色繼承** | ❌ 需要複雜邏輯 | ✅ 自動處理繼承鏈 |
|
|||
|
| **策略語言** | ❌ 硬編碼邏輯 | ✅ 靈活的 DSL |
|
|||
|
| **性能優化** | ❌ 需要自己優化 | ✅ 內建緩存和索引 |
|
|||
|
| **社群支持** | ❌ 需要自己維護 | ✅ 活躍社群,持續更新 |
|
|||
|
| **文檔和範例** | ❌ 需要自己寫文檔 | ✅ 豐富的官方文檔 |
|
|||
|
| **測試覆蓋** | ❌ 需要自己測試 | ✅ 大量生產環境驗證 |
|
|||
|
|
|||
|
## 🚀 進階功能
|
|||
|
|
|||
|
### **ABAC 屬性權限**
|
|||
|
```go
|
|||
|
// 未來可以升級到 ABAC 模型
|
|||
|
// 支援基於用戶屬性、資源屬性、環境屬性的權限控制
|
|||
|
permissionUC.CheckPermissionWithAttributes(ctx,
|
|||
|
map[string]interface{}{
|
|||
|
"user.department": "engineering",
|
|||
|
"resource.owner": "john",
|
|||
|
"time.hour": 9,
|
|||
|
})
|
|||
|
```
|
|||
|
|
|||
|
### **策略管理 API**
|
|||
|
```go
|
|||
|
// 動態管理策略
|
|||
|
policies, err := permissionUC.GetAllPolicies(ctx)
|
|||
|
filtered, err := permissionUC.GetFilteredPolicies(ctx, 0, "role_admin")
|
|||
|
```
|
|||
|
|
|||
|
## 🎯 遷移優勢
|
|||
|
|
|||
|
1. **立即獲得成熟功能** - 通配符、正則表達式、角色繼承
|
|||
|
2. **減少維護成本** - 社群維護,無需自己投入開發時間
|
|||
|
3. **擴展性更強** - 支援複雜的權限模型,適應業務成長
|
|||
|
4. **性能更好** - 內建優化,大量生產環境驗證
|
|||
|
5. **學習成本低** - 豐富的文檔和社群範例
|
|||
|
|
|||
|
## 🔧 立即使用
|
|||
|
|
|||
|
```go
|
|||
|
// 1. 初始化 (自動設置 Casbin)
|
|||
|
PermissionUC: svc.NewPermissionUC(&c, rds),
|
|||
|
|
|||
|
// 2. 添加權限策略
|
|||
|
permissionUC.AddPermissionForRole(ctx, "admin", "/api/users/*", ".*")
|
|||
|
|
|||
|
// 3. 分配角色
|
|||
|
permissionUC.AddRoleForUser(ctx, "john", "admin")
|
|||
|
|
|||
|
// 4. 檢查權限 (自動處理通配符)
|
|||
|
hasPermission, err := permissionUC.CheckUserPermission(ctx, "john", "GET", "/api/users/123")
|
|||
|
```
|
|||
|
|
|||
|
現在你擁有了一個**功能完整、社群驗證、持續維護**的權限系統!🎯
|
|||
|
|
|||
|
**Casbin** 讓你專注於業務邏輯,而不是重新發明權限輪子。
|