GO 權限管理之 Casbin

GO 權限管理之 Casbin

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

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

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

今天我們來分享一下 GO裏面的權限管理,Casbingithub

權限管理是什麼?

通常指根據系統設置的安全規則或者安全策略 算法

用戶能夠訪問並且只能訪問本身被受權的資源,很少很多剛恰好sql

權限管理幾乎出如今任何系統裏面數據庫

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

  • 用戶身份認證

不屬於權限管理範疇segmentfault

用戶身份認證指的是經過某種憑證來證實本身的身份,例如帳號密碼,指紋,人臉識別等等後端

  • 系統管理

是系統中的一個模塊,該模塊通常還含有權限管理子模塊 , 該模塊至關於給權限管理模塊提供了一些數據api

  • 密碼加密

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

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很不錯

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

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

相關文章
相關標籤/搜索