使用casbin做基于RBAC的权限验证
概述
Casbin是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。
Casbin可以
- 支持自定义请求的格式,默认的请求格式为{subject, object, action}。
- 具有访问控制模型model和策略policy两个核心概念。
- 支持RBAC中的多层角色继承,不止主体可以有角色,资源也可以具有角色。
- 支持内置的超级用户 例如:root或administrator。超级用户可以执行任何操作而无需显式的权限声明。
- 支持多种内置的操作符,如 keyMatch,方便对路径式的资源进行管理,如 /foo/bar可以映射到/foo*
Casbin不能
- 身份认证 authentication(即验证用户的用户名、密码),casbin只负责访问控制。应该有其他专门的组件负责身份认证,然后由casbin进行访问控制,二者是相互配合的关系。
- 管理用户列表或角色列表。 Casbin 认为由项目自身来管理用户、角色列表更为合适, 用户通常有他们的密码,但是 Casbin 的设计思想并不是把它作为一个存储密码的容器。 而是存储RBAC方案中用户和角色之间的映射关系。
快速入门
1.安装
1go get github.com/casbin/casbin/v2
2.创建模型文件
model.conf
1[request_definition]
2r = sub, obj, act
3
4[policy_definition]
5p = sub, obj, act
6
7[role_definition]
8g = _, _
9
10[policy_effect]
11e = some(where (p.eft == allow))
12
13[matchers]
14m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
3.创建策略文件
policy.csv
p代表了具体的策略信息,比如alice访问/users的GET访问权限 g代表角色的策略信息,比如alice属于admin组,具有访问/users下的GET和POST权限
1p, alice, /users, GET
2p, bob, /users, POST
3p, admin, /users, GET
4p, admin, /users, POST
5p, admin, /users, DELETE
6g, alice, admin
4.初始化enfocer
1var (
2 e *casbin.Enforcer
3 err error
4)
5
6func init() {
7 e, err = casbin.NewEnforcer("model.conf", "policy.csv")
8 if err != nil {
9 logrus.Fatal("load file failed, %v", err.Error())
10 }
11}
5.定义一个检测权限的函数
1func checkPermission(ctx *gin.Context, sub, obj, act string) {
2 logrus.Infof("sub = %s obj = %s act = %s", sub, obj, act)
3 ok, err := e.Enforce(sub, obj, act)
4 if err != nil {
5 logrus.Print("enforce failed %s", err.Error())
6 ctx.String(http.StatusInternalServerError, "内部服务器错误")
7 return
8 }
9 if !ok {
10 logrus.Println("权限验证不通过")
11 ctx.String(http.StatusOK, "权限验证不通过")
12 return
13 }
14 logrus.Println("权限验证通过")
15 ctx.String(http.StatusOK, "权限验证通过")
16}
6.定义/users下的2个接口
1func main() {
2 r := gin.Default()
3
4 r.GET("/users", func(ctx *gin.Context) {
5 sub := ctx.Query("username")
6 obj := ctx.Request.URL.Path
7 act := ctx.Request.Method
8 checkPermission(ctx, sub, obj, act)
9 })
10 r.POST("/users", func(ctx *gin.Context) {
11 sub := ctx.Query("username")
12 obj := ctx.Request.URL.Path
13 act := ctx.Request.Method
14 checkPermission(ctx, sub, obj, act)
15 })
16
17 r.Run()
18}
7.运行测试
1go run main.go
请求截图
终端输出
API操作
这里使用RBAC中的删除用户操作做演示,更多操作请查看文档API概览
创建结构体
1type PermissionObj struct {
2 User string `json:"user" form:"user"`
3 Sub string `json:"sub" form:"sub"`
4}
增加删除接口
1 r.DELETE("/users", func(ctx *gin.Context) {
2 // 先验证用户权限
3 var p PermissionObj
4 ctx.ShouldBind(&p)
5 obj := ctx.Request.URL.Path
6 act := ctx.Request.Method
7 logrus.Infof("sub = %s obj = %s act = %s", p.User, obj, act)
8 ok, err := e.Enforce(p.User, obj, act)
9 if err != nil {
10 ctx.String(http.StatusInternalServerError, "内部服务器错误")
11 return
12 }
13 if !ok {
14 ctx.String(http.StatusOK, "您没有权限")
15 return
16 }
17 logrus.Println("权限验证通过")
18 // 删除指定用户
19 ok, err = e.DeleteUser(p.Sub)
20 if err != nil {
21 logrus.Info(err.Error())
22 ctx.String(http.StatusInternalServerError, "内部服务器错误")
23 return
24 }
25 if !ok {
26 ctx.String(http.StatusOK, "删除用户失败")
27 return
28 }
29 ctx.String(http.StatusOK, "删除用户成功")
30 e.SavePolicy()
31 })
运行
1go run main.go
删除用户
policy文件
看到bob已经从policy文件中删除了。
更多
想了解更多更详细的用法,可以参考casbin官网
- 原文作者:黄忠德
- 原文链接:https://huangzhongde.cn/post/Golang/%E4%BD%BF%E7%94%A8casbin%E5%81%9A%E5%9F%BA%E4%BA%8ERBAC%E7%9A%84%E6%9D%83%E9%99%90%E9%AA%8C%E8%AF%81/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。