目錄
- 介紹 Casbin 是什么?
- 兩個(gè)核心概念:
- 工作原理:
- 實(shí)戰(zhàn)
- 初始化數(shù)據(jù)庫(kù)
- 用戶權(quán)限的增刪改查
- 總代碼
- 封裝后的代碼
- 參考
本文主要介紹了go語(yǔ)言使用Casbin實(shí)現(xiàn)角色的權(quán)限控制,分享給大家,具體如下:
![](/d/20211017/17709d67ceacd97e690edcca1e0034bd.gif)
介紹 Casbin 是什么?
官方解釋:Casbin是一個(gè)強(qiáng)大的、高效的開源訪問控制框架,其權(quán)限管理機(jī)制支持多種訪問控制模型。
Casbin只負(fù)責(zé)訪問控制。身份認(rèn)證 authentication(即驗(yàn)證用戶的用戶名、密碼),需要其他專門的身份認(rèn)證組件負(fù)責(zé)。例如(jwt-go)
兩個(gè)核心概念:
訪問控制模型model和策略policy。
工作原理:
Casbin把 訪問控制模型 被抽象為基于
PERM元模型 (Policy, Effect, Request, Matchers) [策略,效果,請(qǐng)求,匹配器], 反映了權(quán)限的本質(zhì) – 訪問控制
- Policy: 定義權(quán)限的規(guī)則
- Effect: 定義組合了多個(gè) Policy 之后的結(jié)果, allow/deny
- Request: 訪問請(qǐng)求, 也就是誰(shuí)想操作什么
- Matcher: 判斷 Request 是否滿足 Policy
匹配來源:定義的 request 和 存儲(chǔ)的 police 比對(duì)判斷。
所有 model file 中主要就是定義 PERM 4 個(gè)部分的一個(gè)文件( model.conf , 這個(gè)文件一般是固定的)。
因此,切換或升級(jí)項(xiàng)目的授權(quán)機(jī)制與修改配置一樣簡(jiǎn)單。 您可以通過組合可用的模型來定制您自己的訪問控制模型(ACL, RBAC, ABAC)。
例如,您可以在一個(gè)model中獲得RBAC角色和ABAC屬性,并共享一組policy規(guī)則。
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
實(shí)戰(zhàn)
一般運(yùn)用到項(xiàng)目后臺(tái)的管理權(quán)限中
初始化數(shù)據(jù)庫(kù)
初始化環(huán)境后,系統(tǒng)會(huì)在你選擇的數(shù)據(jù)庫(kù)自動(dòng)生成一個(gè)casbin_rule的數(shù)據(jù)庫(kù)表
![](/d/20211017/b5a97a5c4e3ceec0d64b54460d38eef8.gif)
用戶權(quán)限的增刪改查
tips:這些接口,需要放在截器中間件前面, 不然空表無法添加數(shù)據(jù)
//使用自定義攔截器中間件
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已經(jīng)存在")
} 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)
}
}
})
添加權(quán)限,訪問其添加接口
![](/d/20211017/991ba41f1116bcc9e366a9800ba04190.gif)
單個(gè)用戶保存權(quán)限的路由是多條記錄
![](/d/20211017/5247d044df490d45c3a5a61d690d4cc5.gif)
在使用Casbin中間件時(shí),會(huì)訪問表中的數(shù)據(jù)庫(kù)表 ,得到相應(yīng)的權(quán)限信息,增加訪問信息后,訪問接口成功
![](/d/20211017/742b44a7e1107b2d3dac9ca8111ab31b.gif)
代碼
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("連接數(shù)據(jù)庫(kù)錯(cuò)誤: %v", err)
return
}
e, err := casbin.NewEnforcer("./conf/rbac_models.conf", a)
if err != nil {
log.Printf("初始化casbin錯(cuò)誤: %v", err)
return
}
Enforcer = e
//return e
}
func Hello(c *gin.Context) {
fmt.Println("Hello 接收到GET請(qǐng)求..")
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": "Success",
"data": "Hello 接收到GET請(qǐng)求..",
})
}
func main() {
//獲取router路由對(duì)象
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已經(jīng)存在")
} 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())
//創(chuàng)建請(qǐng)求
r.GET("/api/v1/hello", Hello)
r.Run(":9000") //參數(shù)為空 默認(rèn)監(jiān)聽8080端口
}
//攔截器
func Authorize() gin.HandlerFunc {
return func(c *gin.Context) {
//var e *casbin.Enforcer
e := Enforcer
//從DB加載策略
e.LoadPolicy()
//獲取請(qǐng)求的URI
obj := c.Request.URL.RequestURI()
//獲取請(qǐng)求方法
act := c.Request.Method
//獲取用戶的角色 應(yīng)該從db中讀取
sub := "admin"
//判斷策略中是否存在
if ok, _ := e.Enforce(sub, obj, act); ok {
fmt.Println("恭喜您,權(quán)限驗(yàn)證通過")
c.Next() // 進(jìn)行下一步操作
} else {
fmt.Println("很遺憾,權(quán)限驗(yàn)證沒有通過")
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("連接數(shù)據(jù)庫(kù)錯(cuò)誤: %v", err)
return
}
e, err := casbin.NewEnforcer("./conf/rbac_models.conf", a)
if err != nil {
log.Printf("初始化casbin錯(cuò)誤: %v", err)
return
}
Enforcer = e
//return e
}
func Hello(c *gin.Context) {
fmt.Println("Hello 接收到GET請(qǐng)求..")
c.JSON(http.StatusOK, gin.H{
"code": 200,
"msg": "Success",
"data": "Hello 接收到GET請(qǐng)求..",
})
}
func main() {
//獲取router路由對(duì)象
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已經(jīng)存在")
} 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())
//創(chuàng)建請(qǐng)求
r.GET("/api/v1/hello", Hello)
r.Run(":9000") //參數(shù)為空 默認(rèn)監(jiān)聽8080端口
}
//攔截器
func Authorize() gin.HandlerFunc {
return func(c *gin.Context) {
//var e *casbin.Enforcer
e := Enforcer
//從DB加載策略
e.LoadPolicy()
//獲取請(qǐng)求的URI
obj := c.Request.URL.RequestURI()
//獲取請(qǐng)求方法
act := c.Request.Method
//獲取用戶的角色 應(yīng)該從db中讀取
sub := "admin"
//判斷策略中是否存在
if ok, _ := e.Enforce(sub, obj, act); ok {
fmt.Println("恭喜您,權(quán)限驗(yàn)證通過")
c.Next() // 進(jìn)行下一步操作
} else {
fmt.Println("很遺憾,權(quán)限驗(yàn)證沒有通過")
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"`
}
//添加權(quán)限
func (c *CasbinModel) AddCasbin(cm CasbinModel) bool {
e := Casbin()
e.AddPolicy(cm.RoleName, cm.Path, cm.Method)
return true
}
//持久化到數(shù)據(jù)庫(kù)
// "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
到此這篇關(guān)于go語(yǔ)言使用Casbin實(shí)現(xiàn)角色的權(quán)限控制的文章就介紹到這了,更多相關(guān)go語(yǔ)言角色權(quán)限控制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- Golang之casbin權(quán)限管理的實(shí)現(xiàn)