casbin最牛逼的許可權管理
阿新 • • 發佈:2021-11-22
先上鍊接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.conf
和policy.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
- 建立策略控制檔案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(¶ms)
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。。。。。。