自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Gin集成Casbin進(jìn)行訪問權(quán)限控制

開源
Casbin是一個(gè)強(qiáng)大的、高效的開源訪問控制框架,其權(quán)限管理機(jī)制支持多種訪問控制模型,Casbin只負(fù)責(zé)訪問控制.

[[391016]]

Casbin是什么

Casbin是一個(gè)強(qiáng)大的、高效的開源訪問控制框架,其權(quán)限管理機(jī)制支持多種訪問控制模型,Casbin只負(fù)責(zé)訪問控制[1]。

其功能有:

  • 支持自定義請求的格式,默認(rèn)的請求格式為{subject, object, action}。.
  • 具有訪問控制模型model和策略policy兩個(gè)核心概念。
  • 支持RBAC中的多層角色繼承,不止主體可以有角色,資源也可以具有角色。
  • 支持內(nèi)置的超級(jí)用戶 例如:root或administrator。超級(jí)用戶可以執(zhí)行任何操作而無需顯式的權(quán)限聲明。
  • 支持多種內(nèi)置的操作符,如 keyMatch,方便對路徑式的資源進(jìn)行管理,如 /foo/bar可以映射到 /foo*

Casbin的工作原理

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

  • Policy:定義權(quán)限的規(guī)則
  • Effect:定義組合了多個(gè)Policy之后的結(jié)果
  • Request:訪問請求
  • Matcher:判斷Request是否滿足Policy

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

Casbin的核心概念

Model

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

  • Model CONF 至少應(yīng)包含四個(gè)部分: [request_definition], [policy_definition], [policy_effect], [matchers]。
  • 如果 model 使用 RBAC, 還需要添加[role_definition]部分。
  • Model CONF 文件可以包含注釋。注釋以 # 開頭, # 會(huì)注釋該行剩余部分。

比如:

  1. # Request定義 
  2. [request_definition] 
  3. r = sub, obj, act 
  4.  
  5. # 策略定義 
  6. [policy_definition] 
  7. p = sub, obj, act 
  8.  
  9. # 角色定義 
  10. [role_definition] 
  11. g = _, _ 
  12.  
  13. [policy_effect] 
  14. e = some(where (p.eft == allow)) 
  15.  
  16. # 匹配器定義 
  17. [matchers] 
  18. m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act 
  • request_definition:用于request的定義,它明確了e.Enforce(...)函數(shù)中參數(shù)的定義,sub, obj, act 表示經(jīng)典三元組: 訪問實(shí)體 (Subject),訪問資源 (Object) 和訪問方法 (Action)。
  • policy_definition:用于policy的定義,每條規(guī)則通常以形如p的policy type開頭,比如p,joker,data1,read就是一條joker具有data1讀權(quán)限的規(guī)則。
  • role_definition:是RBAC角色繼承關(guān)系的定義。g 是一個(gè) RBAC系統(tǒng),_, _表示角色繼承關(guān)系的前項(xiàng)和后項(xiàng),即前項(xiàng)繼承后項(xiàng)角色的權(quán)限。
  • policy_effect:是對policy生效范圍的定義,它對request的決策結(jié)果進(jìn)行統(tǒng)一的決策,比如e = some(where (p.eft == allow))就表示如果存在任意一個(gè)決策結(jié)果為allow的匹配規(guī)則,則最終決策結(jié)果為allow。p.eft 表示策略規(guī)則的決策結(jié)果,可以為allow 或者deny,當(dāng)不指定規(guī)則的決策結(jié)果時(shí),取默認(rèn)值allow 。
  • matchers:定義了策略匹配者。匹配者是一組表達(dá)式,它定義了如何根據(jù)請求來匹配策略規(guī)則

Policy

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

比如:

  1. p, alice, data1, read 
  2. p, bob, data2, write 
  3. p, data2_admin, data2, read 
  4. p, data2_admin, data2, write 
  5. g, alice, data2_admin 

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

實(shí)踐

創(chuàng)建項(xiàng)目

首先創(chuàng)建一個(gè)項(xiàng)目,叫casbin_test。

項(xiàng)目里的目錄結(jié)構(gòu)如下:

  1. ├─configs         # 配置文件 
  2. ├─global      # 全局變量 
  3. ├─internal        # 內(nèi)部模塊 
  4. │  ├─dao     # 數(shù)據(jù)處理模塊 
  5. │  ├─middleware   # 中間件 
  6. │  ├─model        # 模型層 
  7. │  ├─router       # 路由 
  8. │  │  └─api 
  9. │  │      └─v1    # 視圖 
  10. │  └─service      # 業(yè)務(wù)邏輯層 
  11. └─pkg             # 內(nèi)部模塊包 
  12.     ├─app         # 應(yīng)用包 
  13.     ├─errcode     # 錯(cuò)誤代碼包 
  14.     └─setting     # 配置包 

下載依賴包,如下:

  1. go get -u github.com/gin-gonic/gin 
  2. # Go語言casbin的依賴包 
  3. go get github.com/casbin/casbin 
  4. # gorm 適配器依賴包 
  5. go get github.com/casbin/gorm-adapter 
  6. # mysql驅(qū)動(dòng)依賴 
  7. go get github.com/go-sql-driver/mysql 
  8. # gorm 包 
  9. go get github.com/jinzhu/gorm 

創(chuàng)建數(shù)據(jù)庫,如下:

  1. CREATE DATABASE `casbin_test` DEFAULT CHARACTER SET utf8; 
  2. GRANT AlterAlter Routine, CreateCreate Routine, Create Temporary Tables, Create ViewDeleteDrop, Event, ExecuteIndexInsert, Lock Tables, ReferencesSelect, Show ViewTriggerUpdate ON `casbin\_test`.* TO `ops`@`%`; 
  3. FLUSH PRIVILEGES
  4. DROP TABLE IF EXIST `casbin_rule`; 
  5. CREATE TABLE `casbin_rule` ( 
  6.   `p_type` varchar(100) DEFAULT NULL COMMENT '規(guī)則類型'
  7.   `v0` varchar(100) DEFAULT NULL COMMENT '角色I(xiàn)D'
  8.   `v1` varchar(100) DEFAULT NULL COMMENT 'api路徑'
  9.   `v2` varchar(100) DEFAULT NULL COMMENT 'api訪問方法'
  10.   `v3` varchar(100) DEFAULT NULL
  11.   `v4` varchar(100) DEFAULT NULL
  12.   `v5` varchar(100) DEFAULT NULL 
  13. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='權(quán)限規(guī)則表'
  14. /*插入操作casbin api的權(quán)限規(guī)則*/ 
  15. INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`) VALUES ('p''admin''/api/v1/casbin''POST'); 
  16. INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`) VALUES ('p''admin''/api/v1/casbin/list''GET'); 

代碼開發(fā)

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

(1)首先在configs目錄下創(chuàng)建rbac_model.conf文件,寫入如下代碼:

  1. [request_definition] 
  2. r = sub, obj, act 
  3.  
  4. [policy_definition] 
  5. p = sub, obj, act 
  6.  
  7. [role_definition] 
  8. g = _, _ 
  9.  
  10. [policy_effect] 
  11. e = some(where (p.eft == allow)) 
  12.  
  13. [matchers] 
  14. m = r.sub == p.sub && ParamsMatch(r.obj,p.obj) && r.act == p.act 

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

  1. type CasbinModel struct { 
  2.  PType  string `json:"p_type" gorm:"column:p_type" description:"策略類型"
  3.  RoleId string `json:"role_id" gorm:"column:v0" description:"角色I(xiàn)D"
  4.  Path   string `json:"path" gorm:"column:v1" description:"api路徑"
  5.  Method string `json:"method" gorm:"column:v2" description:"訪問方法"
  6.  
  7. func (c *CasbinModel) TableName() string { 
  8.  return "casbin_rule" 
  9.  
  10. func (c *CasbinModel) Create(db *gorm.DB) error { 
  11.  e := Casbin() 
  12.  if success := e.AddPolicy(c.RoleId,c.Path,c.Method); success == false { 
  13.   return errors.New("存在相同的API,添加失敗"
  14.  } 
  15.  return nil 
  16.  
  17. func (c *CasbinModel) Update(db *gorm.DB, values interface{}) error { 
  18.  if err := db.Model(c).Where("v1 = ? AND v2 = ?", c.Path, c.Method).Update(values).Error; err != nil { 
  19.   return err 
  20.  } 
  21.  return nil 
  22.  
  23. func (c *CasbinModel) List(db *gorm.DB) [][]string { 
  24.  e := Casbin() 
  25.  policy := e.GetFilteredPolicy(0, c.RoleId) 
  26.  return policy 
  27.  
  28. //@function: Casbin 
  29. //@description: 持久化到數(shù)據(jù)庫  引入自定義規(guī)則 
  30. //@return: *casbin.Enforcer 
  31. func Casbin() *casbin.Enforcer { 
  32.  s := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s&parseTime=%t&loc=Local"
  33.   global.DatabaseSetting.Username, 
  34.   global.DatabaseSetting.Password
  35.   global.DatabaseSetting.Host, 
  36.   global.DatabaseSetting.DBName, 
  37.   global.DatabaseSetting.Charset, 
  38.   global.DatabaseSetting.ParseTime, 
  39.  ) 
  40.  db, _ := gorm.Open(global.DatabaseSetting.DBType, s) 
  41.  
  42.  adapter := gormadapter.NewAdapterByDB(db) 
  43.  enforcer := casbin.NewEnforcer(global.CasbinSetting.ModelPath, adapter) 
  44.  enforcer.AddFunction("ParamsMatch", ParamsMatchFunc) 
  45.  _ = enforcer.LoadPolicy() 
  46.  return enforcer 
  47.  
  48. //@function: ParamsMatch 
  49. //@description: 自定義規(guī)則函數(shù) 
  50. //@param: fullNameKey1 string, key2 string 
  51. //@return: bool 
  52. func ParamsMatch(fullNameKey1 string, key2 string) bool { 
  53.  key1 := strings.Split(fullNameKey1, "?")[0] 
  54.  // 剝離路徑后再使用casbin的keyMatch2 
  55.  return util.KeyMatch2(key1, key2) 
  56.  
  57. //@function: ParamsMatchFunc 
  58. //@description: 自定義規(guī)則函數(shù) 
  59. //@param: args ...interface{} 
  60. //@return: interface{}, error 
  61. func ParamsMatchFunc(args ...interface{}) (interface{}, error) { 
  62.  name1 := args[0].(string) 
  63.  name2 := args[1].(string) 
  64.  
  65.  return ParamsMatch(name1, name2), nil 

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

  1. func (d *Dao) CasbinCreate(roleId string, path, method string) error { 
  2.  cm := model.CasbinModel{ 
  3.   PType:  "p"
  4.   RoleId: roleId, 
  5.   Path:   path, 
  6.   Method: method, 
  7.  } 
  8.  return cm.Create(d.engine) 
  9.  
  10. func (d *Dao) CasbinList(roleID string) [][]string { 
  11.  cm := model.CasbinModel{RoleId: roleID} 
  12.  return cm.List(d.engine) 

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

  1. type CasbinInfo struct { 
  2.  Path   string `json:"path" form:"path"
  3.  Method string `json:"method" form:"method"
  4. type CasbinCreateRequest struct { 
  5.  RoleId      string       `json:"role_id" form:"role_id" description:"角色I(xiàn)D"
  6.  CasbinInfos []CasbinInfo `json:"casbin_infos" description:"權(quán)限模型列表"
  7.  
  8. type CasbinListResponse struct { 
  9.  List []CasbinInfo `json:"list" form:"list"
  10.  
  11. type CasbinListRequest struct { 
  12.  RoleID string `json:"role_id" form:"role_id"
  13.  
  14. func (s Service) CasbinCreate(param *CasbinCreateRequest) error { 
  15.  for _, v := range param.CasbinInfos { 
  16.   err := s.dao.CasbinCreate(param.RoleId, v.Path, v.Method) 
  17.   if err != nil { 
  18.    return err 
  19.   } 
  20.  } 
  21.  return nil 
  22.  
  23.  
  24. func (s Service) CasbinList(param *CasbinListRequest) [][]string { 
  25.  return s.dao.CasbinList(param.RoleID) 

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

  1. type Casbin struct { 
  2.  
  3. func NewCasbin() Casbin { 
  4.  return Casbin{} 
  5.  
  6. // Create godoc 
  7. // @Summary 新增權(quán)限 
  8. // @Description 新增權(quán)限 
  9. // @Tags 權(quán)限管理 
  10. // @Produce json 
  11. // @Security ApiKeyAuth 
  12. // @Param body body service.CasbinCreateRequest true "body" 
  13. // @Success 200 {object} string "成功" 
  14. // @Failure 400 {object} errcode.Error "請求錯(cuò)誤" 
  15. // @Failure 500 {object} errcode.Error "內(nèi)部錯(cuò)誤" 
  16. // @Router /api/v1/casbin [post] 
  17. func (c Casbin) Create(ctx *gin.Context) { 
  18.  param := service.CasbinCreateRequest{} 
  19.  response := app.NewResponse(ctx) 
  20.  valid, errors := app.BindAndValid(ctx, &param) 
  21.  if !valid { 
  22.   log.Printf("app.BindAndValid errs: %v", errors) 
  23.   errRsp := errcode.InvalidParams.WithDetails(errors.Errors()...) 
  24.   response.ToErrorResponse(errRsp) 
  25.   return 
  26.  } 
  27.  
  28.  // 進(jìn)行插入操作 
  29.  svc := service.NewService(ctx) 
  30.  err := svc.CasbinCreate(&param) 
  31.  if err != nil { 
  32.   log.Printf("svc.CasbinCreate err: %v", err) 
  33.   response.ToErrorResponse(errcode.ErrorCasbinCreateFail) 
  34.  } 
  35.  response.ToResponse(gin.H{}) 
  36.  return 
  37.  
  38.  
  39. // List godoc 
  40. // @Summary 獲取權(quán)限列表 
  41. // @Produce json 
  42. // @Tags 權(quán)限管理 
  43. // @Security ApiKeyAuth 
  44. // @Param data body service.CasbinListRequest true "角色I(xiàn)D" 
  45. // @Success 200 {object} service.CasbinListResponse "成功" 
  46. // @Failure 400 {object} errcode.Error "請求錯(cuò)誤" 
  47. // @Failure 500 {object} errcode.Error "內(nèi)部錯(cuò)誤" 
  48. // @Router /api/v1/casbin/list [post] 
  49. func (c Casbin) List(ctx *gin.Context) { 
  50.  param := service.CasbinListRequest{} 
  51.  response := app.NewResponse(ctx) 
  52.  valid, errors := app.BindAndValid(ctx, &param) 
  53.  if !valid { 
  54.   log.Printf("app.BindAndValid errs: %v", errors) 
  55.   errRsp := errcode.InvalidParams.WithDetails(errors.Errors()...) 
  56.   response.ToErrorResponse(errRsp) 
  57.   return 
  58.  } 
  59.  // 業(yè)務(wù)邏輯處理 
  60.  svc := service.NewService(ctx) 
  61.  casbins := svc.CasbinList(&param) 
  62.  var respList []service.CasbinInfo 
  63.  for _, host := range casbins { 
  64.   respList = append(respList, service.CasbinInfo{ 
  65.    Path:   host[1], 
  66.    Method: host[2], 
  67.   }) 
  68.  } 
  69.  response.ToResponseList(respList, 0) 
  70.  return 

再在該目錄下創(chuàng)建一個(gè)test.go文件,用于測試,代碼如下:

  1. type Test struct { 
  2.  
  3. func NewTest() Test { 
  4.  return Test{} 
  5.  
  6. func (t Test) Get(ctx *gin.Context) { 
  7.  log.Println("Hello 接收到GET請求.."
  8.  response := app.NewResponse(ctx) 
  9.  response.ToResponse("接收GET請求成功"

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

  1. func CasbinHandler() gin.HandlerFunc { 
  2.  return func(ctx *gin.Context) { 
  3.   response := app.NewResponse(ctx) 
  4.   // 獲取請求的URI 
  5.   obj := ctx.Request.URL.RequestURI() 
  6.   // 獲取請求方法 
  7.   act := ctx.Request.Method 
  8.   // 獲取用戶的角色 
  9.   sub := "admin" 
  10.   e := model.Casbin() 
  11.   fmt.Println(obj, act, sub) 
  12.   // 判斷策略中是否存在 
  13.   success := e.Enforce(sub, obj, act) 
  14.   if success { 
  15.    log.Println("恭喜您,權(quán)限驗(yàn)證通過"
  16.    ctx.Next() 
  17.   } else { 
  18.    log.Printf("e.Enforce err: %s""很遺憾,權(quán)限驗(yàn)證沒有通過"
  19.    response.ToErrorResponse(errcode.UnauthorizedAuthFail) 
  20.    ctx.Abort() 
  21.    return 
  22.   } 
  23.  } 

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

  1. func NewRouter() *gin.Engine { 
  2.  r := gin.New() 
  3.  r.Use(gin.Logger()) 
  4.  r.Use(gin.Recovery()) 
  5.  casbin := v1.NewCasbin() 
  6.  test := v1.NewTest() 
  7.  apiv1 := r.Group("/api/v1"
  8.  apiv1.Use(middleware.CasbinHandler()) 
  9.  { 
  10.   // 測試路由 
  11.   apiv1.GET("/hello", test.Get) 
  12.  
  13.   // 權(quán)限策略管理 
  14.   apiv1.POST("/casbin", casbin.Create
  15.   apiv1.POST("/casbin/list", casbin.List) 
  16.  } 
  17.  return r 

最后就啟動(dòng)項(xiàng)目進(jìn)行測試。

驗(yàn)證

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


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


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

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


參考文檔:

[1] https://casbin.org/

[2] https://casbin.org/docs/zh-CN/overview

[3] https://gitee.com/coolops/casbin_test.git

 

責(zé)任編輯:姜華 來源: 運(yùn)維開發(fā)故事
相關(guān)推薦

2021-08-09 07:29:54

PythonCasbinPython基礎(chǔ)

2019-07-30 15:13:30

2023-08-07 08:13:41

2010-07-19 21:31:42

2023-08-07 15:23:28

鴻蒙首次啟動(dòng)申請授權(quán)

2022-01-07 07:29:08

Rbac權(quán)限模型

2016-10-12 15:11:56

2011-09-01 12:42:09

SQL Server創(chuàng)建加密視圖控制視圖頁面的訪問權(quán)限

2021-07-21 09:03:53

GoogleChrome權(quán)限

2011-09-01 12:53:02

SQL Server控制視圖頁面的訪問權(quán)限

2013-03-26 13:38:12

Android per

2012-11-15 10:42:10

云集成大數(shù)據(jù)云應(yīng)用集成

2009-09-24 13:47:05

IIS安全配置web服務(wù)器訪問控制

2011-08-03 10:01:28

網(wǎng)絡(luò)智能手機(jī)

2011-08-03 10:20:27

網(wǎng)絡(luò)智能手機(jī)

2011-03-03 11:13:11

Pureftpd

2011-03-03 15:02:22

proftpd權(quán)限

2009-02-05 10:12:00

訪問控制列表限制訪問

2013-05-14 10:37:10

AIR Android設(shè)置訪問權(quán)限

2020-12-23 09:40:17

物聯(lián)網(wǎng)安全訪問控制
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)