GO 權限管理之 Casbin
我們來回顧一下上次分享的 GO中 gjson
庫的應用和分享,它主要是提供了一種非常快速且簡單的方式從json
文檔中獲取相應值
- 分享了
json
與gjson
分別代表什么 gjson
的簡單使用gjson
校驗,獲取值gjson
的json 行
gjson
的鍵路徑匹配規則gjson
的修飾符和自定義修飾符
要是對 gjson
還有點興趣的話,可以查看文章 GO中gjson的應用和分享
今天咱們來分享一下 GO里面的權限管理,Casbin
權限管理是什么?
一般指根據系統設置的安全規則或者安全策略
用戶可以訪問而且只能訪問自己被授權的資源,不多不少剛剛好
權限管理幾乎出現在任何系統里面
我們可能會把 用戶身份認證
、 密碼加密
、 系統管理
與權限管理弄混淆,那么他們具體的側重點是什么呢?
- 用戶身份認證
不屬於權限管理范疇
用戶身份認證指的是通過某種憑證來證明自己的身份,例如賬號密碼,指紋,人臉識別等等
- 系統管理
是系統中的一個模塊,該模塊一般還含有權限管理子模塊 , 該模塊相當於給權限管理模塊提供了一些數據
- 密碼加密
也是不屬於權限管理范疇 , 他只是用戶身份認證領域的一個部分
Casbin 是個啥?
是 GO 項目的功能強大且高效的開源訪問控制庫,casbin
支持常用的多種訪問控制模型,例如:
RBAC
ABAC
ACL
使用casbin
來做權限管理有一個比較好的地方是,casbin
是支持多種語言的,就像protobuf一樣也是支持多種語言
咱們來看看 Casbin 有啥特性
- 實施策略是這樣子的
{subject, object, action}
,
我們也可以自定義,同時他支持允許授權和拒絕授權
- 他可以處理訪問控制模型以及其存儲對應的策略
- 在
RBAC
中的角色層次結構 中,他可以管理角色用戶映射和角色角色映射 - 他支持內置的超級用戶
如root
或administrator
- 支持多個內置運算符規則匹配
例如 hello/world
,就可以將其映射到 hello*模式
- 不支持身份驗證
- 不支持管理用戶或角色列表
咱們看一下 Casbin
的基本模型
在 Casbin
庫中,他是基於PERM
元模型將訪問控制模型抽象為CONF文件,有如下4個部分
- 策略
- 效果
- 請求
- 匹配器
一起來了解一個最簡單的模型,ACL
的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 = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
例如一個ACL
模型的示例策略
p, xiaomt, data1, read
p, xiaomt, data2, write
咱們來寫一個DEMO
main.go
文件寫gin
對應的接口以及casbin
的使用rbac_models.conf
RBAC CONF文件
咱們寫一個路由,里面添加一個攔截器,再寫一個接口/api/v1/hello
,使用GET方法驗證效果
package main
import (
"fmt"
"log"
"github.com/casbin/casbin"
xd "github.com/casbin/xorm-adapter"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
)
// myAuth 攔截器
func myAuth(e *casbin.Enforcer) gin.HandlerFunc {
return func(c *gin.Context) {
obj := c.Request.URL.RequestURI()
// 獲取方法
act := c.Request.Method
sub := "root"
// 判斷策略是否已經存在了
if ok := e.Enforce(sub, obj, act); ok {
log.Println("Check successfully")
c.Next()
} else {
log.Println("sorry , Check failed")
c.Abort()
}
}
}
func main() {
// 使用自己定義rbac_db
// 最后的一個參數咱們寫true ,否則默認為false,使用缺省的數據庫名casbin,不存在則創建
a := xd.NewAdapter("mysql", "root:123456@tcp(127.0.0.1:3306)/mycasbin?charset=utf8", true)
e := casbin.NewEnforcer("./rbac_models.conf", a)
//從DB中 load 策略
e.LoadPolicy()
//new 一個路由
r := gin.New()
r.POST("/api/v1/add", func(c *gin.Context) {
log.Println("add a policy")
if ok := e.AddPolicy("root", "/api/v1/hello", "GET"); !ok {
log.Println("The strategy already exists")
} else {
log.Println("add successfully ...")
}
})
//使用自定義攔截器中間件,每一個接口的訪問,都會通過這個攔截器
r.Use(myAuth(e))
//創建請求
r.GET("/api/v1/hello", func(c *gin.Context) {
fmt.Println("hello wolrd")
})
// 監聽 127。0.0.1:8888
r.Run(":8888")
}
對於上述 xd.NewAdapter
讀取數據的操作,咱們可以看看具體實現
具體源碼在 "github.com/casbin/xorm-adapter"
中的 adapter.go
// NewAdapter is the constructor for Adapter.
// dbSpecified is an optional bool parameter. The default value is false.
// It's up to whether you have specified an existing DB in dataSourceName.
// If dbSpecified == true, you need to make sure the DB in dataSourceName exists.
// If dbSpecified == false, the adapter will automatically create a DB named "casbin".
func NewAdapter(driverName string, dataSourceName string, dbSpecified ...bool) *Adapter {
a := &Adapter{}
a.driverName = driverName
a.dataSourceName = dataSourceName
if len(dbSpecified) == 0 {
a.dbSpecified = false
} else if len(dbSpecified) == 1 {
a.dbSpecified = dbSpecified[0]
} else {
panic(errors.New("invalid parameter: dbSpecified"))
}
// Open the DB, create it if not existed.
a.open()
// Call the destructor when the object is released.
runtime.SetFinalizer(a, finalizer)
return a
}
再來看看casbin.NewEnforcer
源碼文件在 "github.com/casbin/casbin"
中 enforcer.go
NewEnforcer
通過文件或 DB 創建一個 enforcer
, 如下是官方的案例寫法,注意如下案例
// e := casbin.NewEnforcer("path/to/basic_model.conf", "path/to/basic_policy.csv")
// MySQL DB:
// a := mysqladapter.NewDBAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/")
// e := casbin.NewEnforcer("path/to/basic_model.conf", a)
func NewEnforcer(params ...interface{}) *Enforcer {
e := &Enforcer{}
parsedParamLen := 0
// 判斷參數個數
if len(params) >= 1 {
enableLog, ok := params[len(params)-1].(bool)
if ok {
e.EnableLog(enableLog)
parsedParamLen++
}
}
// 省略 部分代碼
return e
}
上述代碼,大家感興趣的話,可以將代碼貼到自己的環境中
使用類似postman
工具來訪問接口,查看效果哦,需要配置好mysql
數據庫
對於上述的 gin
和攔截器
若感興趣的話, 可以查看文章
總結
- 分享了權限管理是什么
- Casbin 是什么
- Casbin 的特性
- Casbin 的應用案例
歡迎點贊,關注,收藏
朋友們,你的支持和鼓勵,是我堅持分享,提高質量的動力
好了,本次就到這里,下一次 工作中后端是如何將API提供出去的?swaggo很不錯
技術是開放的,我們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。
我是小魔童哪吒,歡迎點贊關注收藏,下次見~