GO 權限管理之 Casbin


GO 權限管理之 Casbin

我們來回顧一下上次分享的 GO中 gjson 庫的應用和分享,它主要是提供了一種非常快速簡單的方式從json文檔中獲取相應值

  • 分享了 jsongjson分別代表什么
  • gjson 的簡單使用
  • gjson 校驗,獲取值
  • gjsonjson 行
  • gjson的鍵路徑匹配規則
  • gjson的修飾符和自定義修飾符

要是對 gjson還有點興趣的話,可以查看文章 GO中gjson的應用和分享

今天咱們來分享一下 GO里面的權限管理,Casbin

權限管理是什么?

一般指根據系統設置的安全規則或者安全策略

用戶可以訪問而且只能訪問自己被授權的資源,不多不少剛剛好

權限管理幾乎出現在任何系統里面

我們可能會把 用戶身份認證密碼加密系統管理權限管理弄混淆,那么他們具體的側重點是什么呢?

  • 用戶身份認證

不屬於權限管理范疇

用戶身份認證指的是通過某種憑證來證明自己的身份,例如賬號密碼,指紋,人臉識別等等

  • 系統管理

是系統中的一個模塊,該模塊一般還含有權限管理子模塊 , 該模塊相當於給權限管理模塊提供了一些數據

  • 密碼加密

也是不屬於權限管理范疇 , 他只是用戶身份認證領域的一個部分

Casbin 是個啥?

是 GO 項目的功能強大且高效的開源訪問控制庫,casbin支持常用的多種訪問控制模型,例如:

  • RBAC
  • ABAC
  • ACL

使用casbin來做權限管理有一個比較好的地方是,casbin是支持多種語言的,就像protobuf一樣也是支持多種語言

咱們來看看 Casbin 有啥特性

  • 實施策略是這樣子的 {subject, object, action}

我們也可以自定義,同時他支持允許授權和拒絕授權

  • 他可以處理訪問控制模型以及其存儲對應的策略
  • RBAC中的角色層次結構 中,他可以管理角色用戶映射和角色角色映射
  • 他支持內置的超級用戶

rootadministrator

  • 支持多個內置運算符規則匹配

例如 hello/world ,就可以將其映射到 hello*模式

  • 不支持身份驗證
  • 不支持管理用戶或角色列表

咱們看一下 Casbin 的基本模型

Casbin 庫中,他是基於PERM元模型將訪問控制模型抽象為CONF文件,有如下4個部分

  • 策略
  • 效果
  • 請求
  • 匹配器

一起來了解一個最簡單的模型,ACLCONF模型

#請求定義
[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很不錯

技術是開放的,我們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。

我是小魔童哪吒,歡迎點贊關注收藏,下次見~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM