1. 程式人生 > 其它 >casbin最牛逼的許可權管理

casbin最牛逼的許可權管理

先上鍊接casbin官網

casbin能做什麼?

  • 支援多種程式語言Go/Java/Node/PHP/Python/.NET/Rust,一次學習多處運用
  • 支援自定義請求格式,預設格式(subject,object,action)
  • 具有訪問控制模型model和策略policy兩個核心概念
  • 支援RBAC中的多層繼承,不僅subject有角色,object也可以有角色
  • 支援內建的超級使用者,例如root或admin,超級使用者可以執行任何操作而無需顯式的許可權宣告
  • 支援多種內建的操作符,如 keyMatch,方便對路徑式的資源進行管理,如 /foo/bar 可以對映到 /foo*

Casbin 不能做什麼?

  • 身份認證 authentication(即驗證使用者的使用者名稱、密碼),casbin只負責訪問控制。應該有其他專門的元件負責身份認證,然後由casbin進行訪問控制,二者是相互配合的關係。
  • 管理使用者列表或角色列表。 Casbin 認為由專案自身來管理使用者、角色列表更為合適, 使用者通常有他們的密碼,但是 Casbin 的設計思想並不是把它作為一個儲存密碼的容器。 而是儲存RBAC方案中使用者和角色之間的對映關係

快速開始

Casbin使用配置檔案來設定訪問控制模式。

它有兩個配置檔案,model.confpolicy.csv。 其中,model.conf儲存了訪問模型,policy.csv儲存了特定的使用者許可權配置。 Casbin的使用非常精煉。 基本上,我們只需要一個主要結構:enforcer。 當構建這個結構時,model.conf和policy.csv將被載入

mkdir demo && cd demo && go mod init github.com/51op/go-sdk-demo
go get github.com/casbin/casbin/v2
  • 建立model模型檔案model.conf
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[matchers]
m =  r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root" #只要訪問主體是root一律放行。
[policy_effect]
e = some(where (p.eft == allow))

上面模型檔案規定了許可權由sub,obj,act三要素組成,只有在策略列表中有和它完全相同的策略時,該請求才能通過。匹配器的結果可以通過p.eft

獲取,some(where (p.eft == allow))表示只要有一條策略允許即可

  • 建立策略控制檔案policy.csv
p, demo , /user, write #demo使用者對/user有write許可權
p, demo , /order, read #demo使用者對/order有read許可權
p, demo1 , /user/userlist,read #demo1使用者對/user/userlist有read許可權
p, demo2 , /order/orderlist,read #demo2使用者對/order/orderlist有read許可權
  • 檢查許可權
import (
	"fmt"
	"github.com/casbin/casbin/v2"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"testing"
)
func CheckPermi(e *casbin.Enforcer ,sub,obj,act string)  {
	ok, err := e.Enforce(sub, obj, act)
	if err != nil {
		return
	}
	if ok == true {
		fmt.Printf("%s CAN %s %s\n", sub, act, obj)

	} else {
		fmt.Printf("%s CANNOT %s %s\n", sub, act, obj)
	}
}
func TestCasBin( t *testing.T)  {
	e, err := casbin.NewEnforcer("./model.conf", "./policy.csv")
	if err !=nil{
		log.Fatalf("NewEnforecer failed:%v\n", err)
	}

	//基本許可權設定
	CheckPermi(e, "demo", "/user", "read")
	CheckPermi(e, "demo", "/order", "write")
	CheckPermi(e, "demo1", "/user/userlist", "read")
	CheckPermi(e, "demo1", "/order/orderlist", "write")
}

實戰專案 參考

有些程式碼未做抽取勿噴

  • 目錄結構如下:
dnspod/
├── api
│ ├── casbiniapi.go
│ ├── internal
│ │ └── model
│ │     └── casbin.go
├── config
│ ├── config.json
│ ├── config.yaml
│ └── model.conf
├── common
│ ├── global.go
├── Dockerfile
├── docs
│ ├── docs.go
│ ├── swagger.json
│ └── swagger.yaml
├── go.mod
├── go.sum
├── main.go
├── router
│ ├── handler
│ │ └── func.go
│ └── route.go
  • 首先在configs目錄下建立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 = r.sub == p.sub && ParamsMatch(r.obj,p.obj) && r.act == p.act
  • api/internal/model目錄下,建立casbin.go檔案
package model
import (
	"dnspod/common"
	_ "dnspod/common"
	"log"
)
type CasinoModel struct {
	PType string `gorm:"column:p_type" json:"p_type" form:"p_type" description:"策略型別"`
	RoleId string `gorm:"column:v0" json:"role_id" form:"v0" description:"角色id"`
	Path string `gorm:"column:v1" json:"path" form:"v1" description:"api路徑"`
	Method string `gorm:"column:v2" json:"method" form:"v2" description:"方法"`
}
func(c *CasinoModel) TableName()  string {
	return "casbin_rule"
}
func ( c *CasinoModel) AddPolicy() error  {

        if ok,_:=common.CasBin.AddPolicy(c.RoleId,c.Path,c.Method);ok==false{
           return  common.JsonResponse(100,"增加策略失敗")
        }

        return  common.JsonResponse(200,"增加策略成功")

}
  • 在common/目錄下的global.go檔案中增加如下:
func InitCasbinDB() *casbin.Enforcer  {
	cfg:=Initconfig()
	adapter, _ := gormadapter.NewAdapter("mysql", "epai:epai706@tcp(10.10.10.5:3306)/",)
	CasBin, _ = casbin.NewEnforcer(cfg.CasBin.FilePath, adapter)
	CasBin.AddFunction("ParamsMatch",ParamsMatchFunc)
	CasBin.LoadPolicy()
	return  CasBin
}
func ParamsMatch(fullNameKey1 string,key2 string) bool  {
	key1 := strings.Split(fullNameKey1, "?")[0]
	return util.KeyMatch2(key1,key2)
}
//註冊func到casbin
func ParamsMatchFunc(args ...interface{})(interface{},error)  {
	name1 := args[0].(string)
	name2 := args[1].(string)
	return ParamsMatch(name1, name2), nil
}
  • 在router/下的route.go增加請求

      common.InitCasbinDB() //初始化 InitCasbinDB
       //Casbin許可權認證
    	authGroup:=router.Group("/api/v1/auth")
    	{
    		authGroup.POST("/addPolicy",handler.AddPolicy)
    	}
    
  • router/handler目錄下的func.go中增加AddPolicy

//Casbin 許可權管理

type CasbinInfo struct {
	Path   string `json:"path" form:"path"`
	Method string `json:"method" form:"method"`
}
type CasbinCreateRequest struct {
	RoleId      string       `json:"role_id" form:"role_id" description:"角色ID"`
	CasbinInfos []CasbinInfo `json:"casbin_infos" description:"許可權模型列表"`
}
func AddPolicy(c *gin.Context ) {
	log.Printf("==========")
	var params CasbinCreateRequest
	c.ShouldBind(&params)

	for _, v := range params.CasbinInfos {

		log.Println(params.RoleId, v.Path, v.Method)
		err := api.AddPolicyApi(params.RoleId, v.Path, v.Method)
		if err != nil {
		//	c.JSON(http.StatusOK,gin.H{
		//		"res":"bad",
		//	})
		}
	}
	 c.JSON(http.StatusOK,gin.H{
		"res":"ok",
	})
}

  • 在api/目錄下建立casbiniapi.go檔案
package api
import "dnspod/api/internal/model"
func AddPolicyApi(roleId string, path, method string)  error {
	p:=model.CasinoModel{
		PType: "p",
		RoleId: roleId,
		Path: path,
		Method: method,
	}
	p.AddPolicy()
	return nil
}

最後啟動專案

驗證

檢視mysql庫裡資料就有了

【關注我】持續更新ing。。。。。。