Casbin + Gin + Gorm 學習探索


Casbin 是一個強大的,開源的訪問控制框架,權限管理機制支持多種訪問控制模型; 並且支持多種編程語言; 

 文檔地址:https://casbin.org/docs/zh-CN/overview

Gin Golang 的 Web 框架,短小精悍

 文檔地址: https://gin-gonic.com/docs/

Gorm Golang 的 ORM 框架

 文檔地址:http://gorm.book.jasperxu.com/

今天我們要學習的是如何通過Casbin 來控制開發的 API 訪問權限 

##### Casbin 工作原理

  訪問控制模型被抽象為PERM(Policy,Effect,Request,Matcher) 的一個文件,如果切換項目的授權機制只用修改文件即可; 

  Policy: 定義權限的規則 

  Effect: 定義組合多個Policy 后是允許還是拒絕(allow/deny)

  Request: 訪問的請求,可以理解為誰想訪問什么資源

  Matcher:判斷Request 是否滿足Policy ,返回true或false 

##### 在使用Casbin 控制后台接口時使用以下模型

[request_definition]
    r = sub, obj, act
# 請求的規則 
# r 是規則的名稱,sub 為請求的實體,obj 為資源的名稱, act 為請求的實際操作動作 [policy_definition] p
= sub, obj, act # 策略的規則
# 同請求 [role_definition] g
= _, _ # 角色的定義
# g 角色的名稱,第一個位置為用戶,第二個位置為角色,第三個位置為域(在多租戶場景下使用) [policy_effect] e
= some(where (p.eft == allow)) # 任意一條 policy rule 滿足, 則最終結果為 allow [matchers] m = g(r.sub, p.sub) == true \ && keyMatch2(r.obj, p.obj) == true \ && regexMatch(r.act, p.act) == true \ || r.sub == "root"
# 前三個用來匹配上面定義的請求的規則, 最后一個或條件為:如果實體是root 直接通過, 不驗證權限

在理解了Casbin 的工作原理后,實際寫代碼測試一下

需要使用的外部包

go get github.com/casbin/casbin  Casbin 官方庫

go get github.com/casbin/gorm-adapter  Casbin 插件,用來將規則和策略保存到數據庫中

go get github.com/gin-gonic/gin  Go Web 框架

go get github.com/go-sql-driver/mysql  Go MySQL 驅動 

go get github.com/jinzhu/gorm  Go ORMpackage mainimport (    "fmt"    "github.com/casbin/casbin"

 "github.com/casbin/gorm-adapter" "github.com/gin-gonic/gin" _ "github.com/go-sql-driver/mysql" "github.com/jinzhu/gorm" ) 
// 統一響應結構體 type Response
struct { Code int `json:"code"` Message string `json:"message"` Data interface{} `json:"data"` } var O *gorm.DB var PO *gormadapter.Adapter var Enforcer *casbin.Enforcer
func ping(c
*gin.Context) { var response Response response.Code = 0 response.Message = "success" response.Data = "" c.JSON(200, response) return } // 數據庫連接及角色規則的初始化 func connect() { dsn := "xxx:xxx@(xxxx:3xx6)/goapp?charset=utf8&parseTime=True&loc=Local" var err error O, err = gorm.Open("mysql", dsn) if err != nil { fmt.Println("connect DB error") panic(err) }
   // 將數據庫連接同步給插件, 插件用來操作數據庫 PO
= gormadapter.NewAdapterByDB(O)
// 這里也可以使用原生字符串方式
// Enforcer
= casbin.NewEnforcer("./auth_model.conf", PO)
// 開啟權限認證日志 Enforcer.EnableLog(
true)
// 加載數據庫中的策略 err
= Enforcer.LoadPolicy() if err != nil { fmt.Println("loadPolicy error") panic(err) } // 創建一個角色,並賦於權限
// admin 這個角色可以訪問GET 方式訪問 /api/v2/ping res := Enforcer.AddPolicy("admin","/api/v2/ping","GET") if !res { fmt.Println("policy is exist") } else { fmt.Println("policy is not exist, adding") } // 將 test 用戶加入一個角色中 Enforcer.AddRoleForUser("test","root")
Enforcer.AddRoleForUser("tom","admin")
// 請看規則中如果用戶名為 root 則不受限制 } func main() { defer O.Close() connect() g := gin.Default()
  // 這里的接口沒有使用權限認證中間件 version1 :
= g.Group("/api/v1") { version1.GET("/ping", ping) // 這個是通用的接口 }
// 接口使用權限認證中間件 version2 :
= g.Group("/api/v2", CasbinMiddleWare) { version2.GET("/ping", ping) } _ = g.Run(":8099") } // casbin middleware 權限認證中間件 func CasbinMiddleWare(c *gin.Context) { var userName string userName = c.GetHeader("userName") if userName == "" { fmt.Println("headers invalid") c.JSON(200, gin.H{ "code": 401, "message": "Unauthorized", "data": "", }) c.Abort() return } // 請求的path p := c.Request.URL.Path // 請求的方法 m := c.Request.Method
// 這里認證 res,err := Enforcer.EnforceSafe(userName,p,m) // 這個 HasPermissionForUser 跟上面的有什么區別
// EnforceSafe 會驗證角色的相關的權限
// 而 HasPermissionForUser 只驗證用戶是否有權限
//res = Enforcer.HasPermissionForUser(userName,p,m) if err != nil { fmt.Println("no permission ") fmt.Println(err) c.JSON(200, gin.H{ "code": 401, "message": "Unauthorized", "data": "", }) c.Abort() return } if !res { fmt.Println("permission check failed") c.JSON(200, gin.H{ "code": 401, "message": "Unauthorized", "data": "", }) c.Abort() return } c.Next() }

 

程序運行后數據庫數據為

 

 

 

 

 p 代表的是策略 admin 角色可以使用GET 訪問 /api/v2/ping 

 g 代表的是角色 test 用戶在root 角色中

                           tom 在admin 角色中

所以在測試時請求頭

userName = root 有正常響應 (這里不會到數據庫驗證,策略最后一條)

userName = tom 正常響應 (tom 有admin 角色 , 所以驗證通過)

userName = role_admin 正常響應 (參考這里:https://casbin.org/docs/zh-CN/rbac , 正常情況下用戶名和角色名稱不應該一樣)

userName = *** 都無法通過認證

########

   最后, 一般的后台開發不會這樣設計, 后面繼續學習,理解 Casbin 工作原理,為以后開發打下基礎; 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM