GO 权限治理之 Casbin
咱们来回顾一下上次分享的 GO 中 gjson
库的利用和分享,它次要是提供了一种 十分疾速 且简略 的形式从 json
文档中获取相应值
- 分享了
json
与gjson
别离代表什么 gjson
的简略应用gjson
校验,获取值gjson
的json 行
gjson
的键门路匹配规定gjson
的修饰符和自定义修饰符
要是对 gjson
还有点趣味的话,能够查看文章 GO 中 gjson 的利用和分享
明天咱们来分享一下 GO 外面的权限治理,Casbin
权限治理是什么?
个别指 依据零碎设置的平安规定或者安全策略
用户能够拜访而且只能拜访本人被受权的资源,不多不少刚刚好
权限治理简直呈现在任何零碎外面
咱们可能会把 用户身份认证
、 明码加密
、 系统管理
与 权限治理 弄混同,那么他们具体的侧重点是什么呢?
- 用户身份认证
不属于权限治理领域
用户身份认证指的是通过某种凭证来证实本人的身份,例如账号密码,指纹,人脸识别等等
- 系统管理
是零碎中的一个模块,该模块个别还含有权限治理子模块,该模块相当于给权限治理模块提供了一些数据
- 明码加密
也是不属于权限治理领域,他只是用户身份认证畛域的一个局部
Casbin 是个啥?
是 GO 我的项目的功能强大且高效的开源访问控制库,casbin
反对罕用的多种访问控制模型,例如:
RBAC
ABAC
ACL
应用 casbin
来做权限治理有一个比拟好的中央是,casbin
是反对多种语言的,就像 protobuf 一样也是反对多种语言
咱们来看看 Casbin 有啥个性
- 施行策略是这样子的
{subject, object, action}
,
咱们也能够自定义,同时他反对容许受权和回绝受权
- 他能够解决 访问控制模型以及其存储对应的策略
- 在
RBAC
中的角色层次结构 中,他能够治理角色用户映射和角色角色映射 - 他反对内置的 超级用户
如 root
或administrator
- 反对多个内置运算符规定匹配
例如 hello/world
,就能够将其映射到 hello* 模式
- 不反对身份验证
- 不反对治理用户或角色列表
咱们看一下 Casbin
的根本模型
在 Casbin
库中,他是基于 PERM
元模型将访问控制模型形象为 CONF 文件,有如下 4 个局部
- 策略
- 成果
- 申请
- 匹配器
一起来理解一个最简略的模型,ACL
的 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 = 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 很不错
技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。
我是 小魔童哪吒,欢送点赞关注珍藏,下次见~