一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - 編程技術 - Gin集成Casbin進行訪問權限控制

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

2021-04-02 23:48運維開發故事喬克 編程技術

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

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 文件可以包含注釋。注釋以 # 開頭, # 會注釋該行剩余部分。

比如:

  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(...)函數中參數的定義,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主要表示訪問控制關于角色、資源、行為的具體映射關系。

比如:

  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 

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

實踐

創建項目

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

項目里的目錄結構如下:

  1. ├─configs         # 配置文件 
  2. ├─global      # 全局變量 
  3. ├─internal        # 內部模塊 
  4. │  ├─dao     # 數據處理模塊 
  5. │  ├─middleware   # 中間件 
  6. │  ├─model        # 模型層 
  7. │  ├─router       # 路由 
  8. │  │  └─api 
  9. │  │      └─v1    # 視圖 
  10. │  └─service      # 業務邏輯層 
  11. └─pkg             # 內部模塊包 
  12.     ├─app         # 應用包 
  13.     ├─errcode     # 錯誤代碼包 
  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驅動依賴 
  7. go get github.com/go-sql-driver/mysql 
  8. # gorm 包 
  9. go get github.com/jinzhu/gorm 

創建數據庫,如下:

  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 '規則類型'
  7.   `v0` varchar(100) DEFAULT NULL COMMENT '角色ID'
  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='權限規則表'
  14. /*插入操作casbin api的權限規則*/ 
  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'); 

代碼開發

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

(1)首先在configs目錄下創建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目錄下,創建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:"角色ID"
  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: 持久化到數據庫  引入自定義規則 
  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: 自定義規則函數 
  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: 自定義規則函數 
  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目錄下創建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目錄下創建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:"角色ID"
  6.  CasbinInfos []CasbinInfo `json:"casbin_infos" description:"權限模型列表"
  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目錄下創建casbin.go,寫入如下代碼:

  1. type Casbin struct { 
  2.  
  3. func NewCasbin() Casbin { 
  4.  return Casbin{} 
  5.  
  6. // Create godoc 
  7. // @Summary 新增權限 
  8. // @Description 新增權限 
  9. // @Tags 權限管理 
  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 "請求錯誤" 
  15. // @Failure 500 {object} errcode.Error "內部錯誤" 
  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.  // 進行插入操作 
  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 獲取權限列表 
  41. // @Produce json 
  42. // @Tags 權限管理 
  43. // @Security ApiKeyAuth 
  44. // @Param data body service.CasbinListRequest true "角色ID" 
  45. // @Success 200 {object} service.CasbinListResponse "成功" 
  46. // @Failure 400 {object} errcode.Error "請求錯誤" 
  47. // @Failure 500 {object} errcode.Error "內部錯誤" 
  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.  // 業務邏輯處理 
  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 

再在該目錄下創建一個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目錄下創建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("恭喜您,權限驗證通過"
  16.    ctx.Next() 
  17.   } else { 
  18.    log.Printf("e.Enforce err: %s""很遺憾,權限驗證沒有通過"
  19.    response.ToErrorResponse(errcode.UnauthorizedAuthFail) 
  20.    ctx.Abort() 
  21.    return 
  22.   } 
  23.  } 

(7)在internal/router目錄下創建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.   // 權限策略管理 
  14.   apiv1.POST("/casbin", casbin.Create
  15.   apiv1.POST("/casbin/list", casbin.List) 
  16.  } 
  17.  return r 

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

驗證

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

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

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

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

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

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

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

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

參考文檔:

[1] https://casbin.org/

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

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

原文地址:https://mp.weixin.qq.com/s/Igi_xWO-XqEIuHOwabSmMg

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久精品观看影院2828 | 国产成人看片免费视频观看 | 日本三级欧美三级人妇英文 | 操姓| 72张让男人一看就硬的图片 | 欧美男同互吃gay老头 | 糖心在线观看网 | 亚洲AV精品无码喷水直播间 | 亚欧视频在线观看 | 男女18一级大黄毛片免 | 久久婷婷五月综合色丁香花 | 国产大片网站 | 5151hh四虎国产精品 | 五月色天在线视频综合观看 | 午夜私人影院在线观看 视频 | 国产盗摄wc厕所撒尿视频 | 菠萝视频5正版在线观看 | 桃色综合网 | 五月精品 | 男女小视频在线观看 | 久久久WWW免费人成精品 | 无码中文字幕av免费放 | 日本四虎影院 | 日韩香蕉视频 | 欧美特黄三级在线观看 | 国产精品1024永久免费视频 | 欧美精品久久久久久久影视 | 人人最怕九月羊 | 桃色视频破解版 | 五月婷婷在线观看 | 免费视频亚洲 | 日韩精品免费一级视频 | 欧美一级特黄aaa大片 | 亚洲精品91在线 | 国产人妖xxxxx免费看 | 亚洲欧美国产精品久久久 | 国产综合亚洲专区在线 | 91sao国产在线观看 | 成人网免费视频 | 亚洲羞羞裸色私人影院 | 色悠久久久久综合网小说 |