乐趣区

关于后端: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 拦截器 若感兴趣的话,能够查看文章

  • 分享一波 gin 的路由算法
  • 瞧一瞧 gRPC 的拦截器
  • Gin 实战演练

总结

  • 分享了权限治理是什么
  • Casbin 是什么
  • Casbin 的个性
  • Casbin 的利用案例

欢送点赞,关注,珍藏

敌人们,你的反对和激励,是我保持分享,提高质量的能源

好了,本次就到这里,下一次 工作中后端是如何将 API 提供进来的?swaggo 很不错

技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。

我是 小魔童哪吒,欢送点赞关注珍藏,下次见~

退出移动版