go語言使用Casbin實現角色的權限控制
本文主要介紹瞭go語言使用Casbin實現角色的權限控制,分享給大傢,具體如下:
介紹 Casbin 是什麼?
官方解釋:Casbin是一個強大的、高效的開源訪問控制框架,其權限管理機制支持多種訪問控制模型。
Casbin隻負責訪問控制。身份認證 authentication(即驗證用戶的用戶名、密碼),需要其他專門的身份認證組件負責。例如(jwt-go)
兩個核心概念:
訪問控制模型model和策略policy。
工作原理:
Casbin把 訪問控制模型 被抽象為基於
PERM元模型 (Policy, Effect, Request, Matchers) [策略,效果,請求,匹配器], 反映瞭權限的本質 – 訪問控制
- Policy: 定義權限的規則
- Effect: 定義組合瞭多個 Policy 之後的結果, allow/deny
- Request: 訪問請求, 也就是誰想操作什麼
- Matcher: 判斷 Request 是否滿足 Policy
匹配來源:定義的 request 和 存儲的 police 比對判斷。
所有 model file 中主要就是定義 PERM 4 個部分的一個文件( model.conf , 這個文件一般是固定的)。
因此,切換或升級項目的授權機制與修改配置一樣簡單。 您可以通過組合可用的模型來定制您自己的訪問控制模型(ACL, RBAC, ABAC)。
例如,您可以在一個model中獲得RBAC角色和ABAC屬性,並共享一組policy規則。
g, g2, g3 表示不同的 RBAC 體系, _, _ 表示用戶和角色 _, _, _ 表示用戶, 角色, 域(也就是租戶)
rbac_models.conf
# Request definition [request_definition] r = sub, obj, act # Policy definition [policy_definition] p = sub, obj, act # Policy effect [policy_effect] e = some(where (p.eft == allow)) # Matchers [matchers] m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
實戰
一般運用到項目後臺的管理權限中
初始化數據庫
初始化環境後,系統會在你選擇的數據庫自動生成一個casbin_rule的數據庫表
用戶權限的增刪改查
tips:這些接口,需要放在截器中間件前面, 不然空表無法添加數據
//使用自定義攔截器中間件 r.Use(Authorize())
//增加policy r.POST("/api/v1/add", func(c *gin.Context) { fmt.Println("增加Policy") if ok, _ := Enforcer.AddPolicy("admin", "/api/v1/world", "GET"); !ok { fmt.Println("Policy已經存在") } else { fmt.Println("增加成功") } }) //刪除policy r.DELETE("/api/v1/delete", func(c *gin.Context) { fmt.Println("刪除Policy") if ok, _ := Enforcer.RemovePolicy("admin", "/api/v1/world", "GET"); !ok { fmt.Println("Policy不存在") } else { fmt.Println("刪除成功") } }) //獲取policy r.GET("/api/v1/get", func(c *gin.Context) { fmt.Println("查看policy") list := Enforcer.GetPolicy() for _, vlist := range list { for _, v := range vlist { fmt.Printf("value: %s, ", v) } } })
添加權限,訪問其添加接口
單個用戶保存權限的路由是多條記錄
在使用Casbin中間件時,會訪問表中的數據庫表 ,得到相應的權限信息,增加訪問信息後,訪問接口成功
代碼
package main import ( "fmt" "github.com/casbin/casbin" xormadapter "github.com/casbin/xorm-adapter" "github.com/gin-gonic/gin" _ "github.com/go-sql-driver/mysql" "log" "net/http" ) var Enforcer *casbin.Enforcer func init() { CasbinSetup() } // 初始化casbin func CasbinSetup(){ a, err := xormadapter.NewAdapter("mysql", "root:root123@tcp(127.0.0.1:3306)/casbin?charset=utf8", true) if err != nil { log.Printf("連接數據庫錯誤: %v", err) return } e, err := casbin.NewEnforcer("./conf/rbac_models.conf", a) if err != nil { log.Printf("初始化casbin錯誤: %v", err) return } Enforcer = e //return e } func Hello(c *gin.Context) { fmt.Println("Hello 接收到GET請求..") c.JSON(http.StatusOK, gin.H{ "code": 200, "msg": "Success", "data": "Hello 接收到GET請求..", }) } func main() { //獲取router路由對象 r := gin.New() //增加policy r.GET("/api/v1/add", func(c *gin.Context) { fmt.Println("增加Policy") if ok, _ := Enforcer.AddPolicy("admin", "/api/v1/world", "GET"); !ok { fmt.Println("Policy已經存在") } else { fmt.Println("增加成功") } }) //刪除policy r.DELETE("/api/v1/delete", func(c *gin.Context) { fmt.Println("刪除Policy") if ok, _ := Enforcer.RemovePolicy("admin", "/api/v1/world", "GET"); !ok { fmt.Println("Policy不存在") } else { fmt.Println("刪除成功") } }) //獲取policy r.GET("/api/v1/get", func(c *gin.Context) { fmt.Println("查看policy") list := Enforcer.GetPolicy() for _, vlist := range list { for _, v := range vlist { fmt.Printf("value: %s, ", v) } } }) //使用自定義攔截器中間件 r.Use(Authorize()) //創建請求 r.GET("/api/v1/hello", Hello) r.Run(":9000") //參數為空 默認監聽8080端口 } //攔截器 func Authorize() gin.HandlerFunc { return func(c *gin.Context) { //var e *casbin.Enforcer e := Enforcer //從DB加載策略 e.LoadPolicy() //獲取請求的URI obj := c.Request.URL.RequestURI() //獲取請求方法 act := c.Request.Method //獲取用戶的角色 應該從db中讀取 sub := "admin" //判斷策略中是否存在 if ok, _ := e.Enforce(sub, obj, act); ok { fmt.Println("恭喜您,權限驗證通過") c.Next() // 進行下一步操作 } else { fmt.Println("很遺憾,權限驗證沒有通過") c.Abort() } } }
總代碼
package main import ( "fmt" "github.com/casbin/casbin" xormadapter "github.com/casbin/xorm-adapter" "github.com/gin-gonic/gin" _ "github.com/go-sql-driver/mysql" "log" "net/http" ) var Enforcer *casbin.Enforcer func init() { CasbinSetup() } // 初始化casbin func CasbinSetup(){ a, err := xormadapter.NewAdapter("mysql", "root:root123@tcp(127.0.0.1:3306)/casbin?charset=utf8", true) if err != nil { log.Printf("連接數據庫錯誤: %v", err) return } e, err := casbin.NewEnforcer("./conf/rbac_models.conf", a) if err != nil { log.Printf("初始化casbin錯誤: %v", err) return } Enforcer = e //return e } func Hello(c *gin.Context) { fmt.Println("Hello 接收到GET請求..") c.JSON(http.StatusOK, gin.H{ "code": 200, "msg": "Success", "data": "Hello 接收到GET請求..", }) } func main() { //獲取router路由對象 r := gin.New() //增加policy r.GET("/api/v1/add", func(c *gin.Context) { fmt.Println("增加Policy") if ok, _ := Enforcer.AddPolicy("admin", "/api/v1/world", "GET"); !ok { fmt.Println("Policy已經存在") } else { fmt.Println("增加成功") } }) //刪除policy r.DELETE("/api/v1/delete", func(c *gin.Context) { fmt.Println("刪除Policy") if ok, _ := Enforcer.RemovePolicy("admin", "/api/v1/world", "GET"); !ok { fmt.Println("Policy不存在") } else { fmt.Println("刪除成功") } }) //獲取policy r.GET("/api/v1/get", func(c *gin.Context) { fmt.Println("查看policy") list := Enforcer.GetPolicy() for _, vlist := range list { for _, v := range vlist { fmt.Printf("value: %s, ", v) } } }) //使用自定義攔截器中間件 r.Use(Authorize()) //創建請求 r.GET("/api/v1/hello", Hello) r.Run(":9000") //參數為空 默認監聽8080端口 } //攔截器 func Authorize() gin.HandlerFunc { return func(c *gin.Context) { //var e *casbin.Enforcer e := Enforcer //從DB加載策略 e.LoadPolicy() //獲取請求的URI obj := c.Request.URL.RequestURI() //獲取請求方法 act := c.Request.Method //獲取用戶的角色 應該從db中讀取 sub := "admin" //判斷策略中是否存在 if ok, _ := e.Enforce(sub, obj, act); ok { fmt.Println("恭喜您,權限驗證通過") c.Next() // 進行下一步操作 } else { fmt.Println("很遺憾,權限驗證沒有通過") c.Abort() } } }
封裝後的代碼
package mycasbin import ( "simple-api/mongoose" "github.com/casbin/mongodb-adapter" "github.com/casbin/casbin" "gopkg.in/mgo.v2/bson" ) type CasbinModel struct { ID bson.ObjectId `json:"id" bson:"_id"` Ptype string `json:"ptype" bson:"ptype"` RoleName string `json:"rolename" bson:"v0"` Path string `json:"path" bson:"v1"` Method string `json:"method" bson:"v2"` } //添加權限 func (c *CasbinModel) AddCasbin(cm CasbinModel) bool { e := Casbin() e.AddPolicy(cm.RoleName, cm.Path, cm.Method) return true } //持久化到數據庫 // "github.com/casbin/mongodb-adapter" // func Casbin() *casbin.Enforcer { // a := mongodbadapter.NewAdapter(mongoose.MongoUrl) // e := casbin.NewEnforcer("conf/auth_model.conf", a) // e.LoadPolicy() // return e // } func Casbin() *casbin.Enforcer { a := mongodbadapter.NewAdapter(mongoose.MongoUrl) e, err := casbin.NewEnforcer("conf/auth_model.conf", a) if err != nil { panic(err) } e.LoadPolicy() return e }
package apis import ( "net/http" "simple-api/utils/mycasbin" "github.com/gin-gonic/gin" "gopkg.in/mgo.v2/bson" ) var ( casbins = mycasbin.CasbinModel{} ) func AddCasbin(c *gin.Context) { rolename := c.PostForm("rolename") path := c.PostForm("path") method := c.PostForm("method") ptype := "p" casbin := mycasbin.CasbinModel{ ID: bson.NewObjectId(), Ptype: ptype, RoleName: rolename, Path: path, Method: method, } isok := casbins.AddCasbin(casbin) if isok { c.JSON(http.StatusOK, gin.H{ "success": true, "msg": "保存成功", }) } else { c.JSON(http.StatusOK, gin.H{ "success": false, "msg": "保存失敗", }) } }
參考
https://www.jianshu.com/p/9506406e745f
到此這篇關於go語言使用Casbin實現角色的權限控制的文章就介紹到這瞭,更多相關go語言角色權限控制內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 如何在Go中使用Casbin進行訪問控制
- Python 權限控制模塊 Casbin
- 如何使用Casbin作為ThinkPHP的權限控制中間件
- Golang基於JWT與Casbin身份驗證授權實例詳解
- 基於Go語言構建RESTful API服務