亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Gin如何集成Casbin進行訪問權限控制

發布時間:2021-12-22 14:12:25 來源:億速云 閱讀:162 作者:小新 欄目:互聯網科技

小編給大家分享一下Gin如何集成Casbin進行訪問權限控制,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

Casbin是什么

Casbin是一個強大的、高效的開源訪問控制框架,其權限管理機制支持多種訪問控制模型,Casbin只負責訪問控制[1]。

其功能有:

  • 支持自定義請求的格式,默認的請求格式為{subject, object, action}。.

  • 具有訪問控制模型model和策略policy兩個核心概念。

  • 支持RBAC中的多層角色繼承,不止主體可以有角色,資源也可以具有角色。

  • 支持內置的超級用戶 例如:root或administrator。超級用戶可以執行任何操作而無需顯式的權限聲明。

  • 支持多種內置的操作符,如 keyMatch,方便對路徑式的資源進行管理,如 /foo/bar可以映射到 /foo*

Casbin的工作原理

在 Casbin 中, 訪問控制模型被抽象為基于 **PERM **(Policy, Effect, Request,  Matcher) [策略,效果,請求,匹配器]的一個文件。

  • Policy:定義權限的規則

  • Effect:定義組合了多個Policy之后的結果

  • Request:訪問請求

  • Matcher:判斷Request是否滿足Policy

首先會定義一堆Policy,然后通過Matcher來判斷Request和Policy是否匹配,然后通過Effect來判斷匹配結果是Allow還是Deny。

Casbin的核心概念

Model

Model是Casbin的具體訪問模型,其主要以文件的形式出現,該文件常常以.conf最為后綴。

  • Model CONF 至少應包含四個部分: [request_definition], [policy_definition],  [policy_effect], [matchers]。

  • 如果 model 使用 RBAC, 還需要添加[role_definition]部分。

  • Model CONF 文件可以包含注釋。注釋以 # 開頭, # 會注釋該行剩余部分。

比如:

# Request定義 [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
  • request_definition:用于request的定義,它明確了e.Enforce(...)函數中參數的定義,sub, obj, act  表示經典三元組: 訪問實體 (Subject),訪問資源 (Object) 和訪問方法 (Action)。

  • policy_definition:用于policy的定義,每條規則通常以形如p的policy  type開頭,比如p,joker,data1,read就是一條joker具有data1讀權限的規則。

  • role_definition:是RBAC角色繼承關系的定義。g 是一個 RBAC系統,_,  _表示角色繼承關系的前項和后項,即前項繼承后項角色的權限。

  • policy_effect:是對policy生效范圍的定義,它對request的決策結果進行統一的決策,比如e = some(where (p.eft  == allow))就表示如果存在任意一個決策結果為allow的匹配規則,則最終決策結果為allow。p.eft 表示策略規則的決策結果,可以為allow  或者deny,當不指定規則的決策結果時,取默認值allow 。

  • matchers:定義了策略匹配者。匹配者是一組表達式,它定義了如何根據請求來匹配策略規則

Policy

Policy主要表示訪問控制關于角色、資源、行為的具體映射關系。

比如:

p, alice, data1, read p, bob, data2, write p, data2_admin, data2, read p, data2_admin, data2, write g, alice, data2_admin

它的關系規則很簡單,主要是選擇什么方式來存儲規則,目前官方提供csv文件存儲和通過adapter適配器從其他存儲系統中加載配置文件,比如MySQL,  PostgreSQL, SQL Server, SQLite3,MongoDB,Redis,Cassandra DB等。

實踐

創建項目

首先創建一個項目,叫casbin_test。

項目里的目錄結構如下:

├─configs         # 配置文件 ├─global      # 全局變量 ├─internal        # 內部模塊 │  ├─dao     # 數據處理模塊 │  ├─middleware   # 中間件 │  ├─model        # 模型層 │  ├─router       # 路由 │  │  └─api │  │      └─v1    # 視圖 │  └─service      # 業務邏輯層 └─pkg             # 內部模塊包     ├─app         # 應用包     ├─errcode     # 錯誤代碼包     └─setting     # 配置包

下載依賴包,如下:

go get -u github.com/gin-gonic/gin # Go語言casbin的依賴包 go get github.com/casbin/casbin # gorm 適配器依賴包 go get github.com/casbin/gorm-adapter # mysql驅動依賴 go get github.com/go-sql-driver/mysql # gorm 包 go get github.com/jinzhu/gorm

創建數據庫,如下:

CREATE DATABASE `casbin_test` DEFAULT CHARACTER SET utf8; GRANT Alter, Alter Routine, Create, Create Routine, Create Temporary Tables, Create View, Delete, Drop, Event, Execute, Index, Insert, Lock Tables, References, Select, Show View, Trigger, Update ON `casbin\_test`.* TO `ops`@`%`; FLUSH PRIVILEGES; DROP TABLE IF EXIST `casbin_rule`; CREATE TABLE `casbin_rule` (   `p_type` varchar(100) DEFAULT NULL COMMENT '規則類型',   `v0` varchar(100) DEFAULT NULL COMMENT '角色ID',   `v1` varchar(100) DEFAULT NULL COMMENT 'api路徑',   `v2` varchar(100) DEFAULT NULL COMMENT 'api訪問方法',   `v3` varchar(100) DEFAULT NULL,   `v4` varchar(100) DEFAULT NULL,   `v5` varchar(100) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='權限規則表'; /*插入操作casbin api的權限規則*/ INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`) VALUES ('p', 'admin', '/api/v1/casbin', 'POST'); INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`) VALUES ('p', 'admin', '/api/v1/casbin/list', 'GET');

代碼開發

由于代碼比較多,這里就不貼全部代碼了,全部代碼已經放在gitee倉庫[3],可以自行閱讀,這些僅僅貼部分關鍵代碼。

(1)首先在configs目錄下創建rbac_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

(2)在internal/model目錄下,創建casbin.go文件,寫入如下代碼:

type CasbinModel struct {  PType  string `json:"p_type" gorm:"column:p_type" description:"策略類型"`  RoleId string `json:"role_id" gorm:"column:v0" description:"角色ID"`  Path   string `json:"path" gorm:"column:v1" description:"api路徑"`  Method string `json:"method" gorm:"column:v2" description:"訪問方法"` }  func (c *CasbinModel) TableName() string {  return "casbin_rule" }  func (c *CasbinModel) Create(db *gorm.DB) error {  e := Casbin()  if success := e.AddPolicy(c.RoleId,c.Path,c.Method); success == false {   return errors.New("存在相同的API,添加失敗")  }  return nil }  func (c *CasbinModel) Update(db *gorm.DB, values interface{}) error {  if err := db.Model(c).Where("v1 = ? AND v2 = ?", c.Path, c.Method).Update(values).Error; err != nil {   return err  }  return nil }  func (c *CasbinModel) List(db *gorm.DB) [][]string {  e := Casbin()  policy := e.GetFilteredPolicy(0, c.RoleId)  return policy }  //@function: Casbin //@description: 持久化到數據庫  引入自定義規則 //@return: *casbin.Enforcer func Casbin() *casbin.Enforcer {  s := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s&parseTime=%t&loc=Local",   global.DatabaseSetting.Username,   global.DatabaseSetting.Password,   global.DatabaseSetting.Host,   global.DatabaseSetting.DBName,   global.DatabaseSetting.Charset,   global.DatabaseSetting.ParseTime,  )  db, _ := gorm.Open(global.DatabaseSetting.DBType, s)   adapter := gormadapter.NewAdapterByDB(db)  enforcer := casbin.NewEnforcer(global.CasbinSetting.ModelPath, adapter)  enforcer.AddFunction("ParamsMatch", ParamsMatchFunc)  _ = enforcer.LoadPolicy()  return enforcer }  //@function: ParamsMatch //@description: 自定義規則函數 //@param: fullNameKey1 string, key2 string //@return: bool func ParamsMatch(fullNameKey1 string, key2 string) bool {  key1 := strings.Split(fullNameKey1, "?")[0]  // 剝離路徑后再使用casbin的keyMatch3  return util.KeyMatch3(key1, key2) }  //@function: ParamsMatchFunc //@description: 自定義規則函數 //@param: args ...interface{} //@return: interface{}, error func ParamsMatchFunc(args ...interface{}) (interface{}, error) {  name1 := args[0].(string)  name2 := args[1].(string)   return ParamsMatch(name1, name2), nil }

(3)在internal/dao目錄下創建casbin.go,寫入如下代碼:

func (d *Dao) CasbinCreate(roleId string, path, method string) error {  cm := model.CasbinModel{   PType:  "p",   RoleId: roleId,   Path:   path,   Method: method,  }  return cm.Create(d.engine) }  func (d *Dao) CasbinList(roleID string) [][]string {  cm := model.CasbinModel{RoleId: roleID}  return cm.List(d.engine) }

(4)在internal/service目錄下創建service.go,寫入如下代碼:

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:"權限模型列表"` }  type CasbinListResponse struct {  List []CasbinInfo `json:"list" form:"list"` }  type CasbinListRequest struct {  RoleID string `json:"role_id" form:"role_id"` }  func (s Service) CasbinCreate(param *CasbinCreateRequest) error {  for _, v := range param.CasbinInfos {   err := s.dao.CasbinCreate(param.RoleId, v.Path, v.Method)   if err != nil {    return err   }  }  return nil }   func (s Service) CasbinList(param *CasbinListRequest) [][]string {  return s.dao.CasbinList(param.RoleID) }

(5)在internal/router/api/v1目錄下創建casbin.go,寫入如下代碼:

type Casbin struct { }  func NewCasbin() Casbin {  return Casbin{} }  // Create godoc // @Summary 新增權限 // @Description 新增權限 // @Tags 權限管理 // @Produce json // @Security ApiKeyAuth // @Param body body service.CasbinCreateRequest true "body" // @Success 200 {object} string "成功" // @Failure 400 {object} errcode.Error "請求錯誤" // @Failure 500 {object} errcode.Error "內部錯誤" // @Router /api/v1/casbin [post] func (c Casbin) Create(ctx *gin.Context) {  param := service.CasbinCreateRequest{}  response := app.NewResponse(ctx)  valid, errors := app.BindAndValid(ctx, &param)  if !valid {   log.Printf("app.BindAndValid errs: %v", errors)   errRsp := errcode.InvalidParams.WithDetails(errors.Errors()...)   response.ToErrorResponse(errRsp)   return  }   // 進行插入操作  svc := service.NewService(ctx)  err := svc.CasbinCreate(&param)  if err != nil {   log.Printf("svc.CasbinCreate err: %v", err)   response.ToErrorResponse(errcode.ErrorCasbinCreateFail)  }  response.ToResponse(gin.H{})  return }   // List godoc // @Summary 獲取權限列表 // @Produce json // @Tags 權限管理 // @Security ApiKeyAuth // @Param data body service.CasbinListRequest true "角色ID" // @Success 200 {object} service.CasbinListResponse "成功" // @Failure 400 {object} errcode.Error "請求錯誤" // @Failure 500 {object} errcode.Error "內部錯誤" // @Router /api/v1/casbin/list [post] func (c Casbin) List(ctx *gin.Context) {  param := service.CasbinListRequest{}  response := app.NewResponse(ctx)  valid, errors := app.BindAndValid(ctx, &param)  if !valid {   log.Printf("app.BindAndValid errs: %v", errors)   errRsp := errcode.InvalidParams.WithDetails(errors.Errors()...)   response.ToErrorResponse(errRsp)   return  }  // 業務邏輯處理  svc := service.NewService(ctx)  casbins := svc.CasbinList(&param)  var respList []service.CasbinInfo  for _, host := range casbins {   respList = append(respList, service.CasbinInfo{    Path:   host[1],    Method: host[2],   })  }  response.ToResponseList(respList, 0)  return }

再在該目錄下創建一個test.go文件,用于測試,代碼如下:

type Test struct { }  func NewTest() Test {  return Test{} }  func (t Test) Get(ctx *gin.Context) {  log.Println("Hello 接收到GET請求..")  response := app.NewResponse(ctx)  response.ToResponse("接收GET請求成功") }

(6)在internal/middleware目錄下創建casbin_handler.go,寫入如下代碼:

func CasbinHandler() gin.HandlerFunc {  return func(ctx *gin.Context) {   response := app.NewResponse(ctx)   // 獲取請求的URI   obj := ctx.Request.URL.RequestURI()   // 獲取請求方法   act := ctx.Request.Method   // 獲取用戶的角色   sub := "admin"   e := model.Casbin()   fmt.Println(obj, act, sub)   // 判斷策略中是否存在   success := e.Enforce(sub, obj, act)   if success {    log.Println("恭喜您,權限驗證通過")    ctx.Next()   } else {    log.Printf("e.Enforce err: %s", "很遺憾,權限驗證沒有通過")    response.ToErrorResponse(errcode.UnauthorizedAuthFail)    ctx.Abort()    return   }  } }

(7)在internal/router目錄下創建router.go,定義路由,代碼如下:

func NewRouter() *gin.Engine {  r := gin.New()  r.Use(gin.Logger())  r.Use(gin.Recovery())  casbin := v1.NewCasbin()  test := v1.NewTest()  apiv1 := r.Group("/api/v1")  apiv1.Use(middleware.CasbinHandler())  {   // 測試路由   apiv1.GET("/hello", test.Get)    // 權限策略管理   apiv1.POST("/casbin", casbin.Create)   apiv1.POST("/casbin/list", casbin.List)  }  return r }

最后就啟動項目進行測試。

驗證

(1)首先訪問測試路徑,當前情況下沒在權限表里,如下:

Gin如何集成Casbin進行訪問權限控制

(2)將測試路徑添加到權限列表,如下:

Gin如何集成Casbin進行訪問權限控制

(3)然后再次訪問測試路徑,如下:

Gin如何集成Casbin進行訪問權限控制

并且從日志上也可以看到,如下:

Gin如何集成Casbin進行訪問權限控制

以上是“Gin如何集成Casbin進行訪問權限控制”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

高碑店市| 稷山县| 深州市| 遵义市| 华宁县| 克山县| 高清| 汾西县| 河北区| 盐亭县| 沙坪坝区| 乐平市| 扶风县| 宣汉县| 永年县| 常州市| 清丰县| 武宣县| 叶城县| 都兰县| 宁强县| 华亭县| 额敏县| 微博| 毕节市| 壤塘县| 石首市| 黄梅县| 五华县| 丰县| 镇江市| 彰化县| 芦山县| 奉新县| 宜君县| 上饶市| 乌苏市| 宿松县| 鄯善县| 当涂县| 石泉县|