casbin轻量级访问控制框架基本使用

Casbin是一个强大的,高效的开源访问控制框架,其权限管理机制支持多种访问控制模型,支持多种编程语言。

基本使用

go get github.com/casbin/casbin/v2

casbin有两个部分组成,一个是配置文件,一个是规则集

demo如下
首先准备两个文件,model.pml和policy.csv文件
model.pml

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

[policy_effect]
e = some(where (p.eft == allow))

policy.csv

p, xiaoming, /hello, GET
p, xiaoming, /hello/go, GET
p, xiaoming, /user, GET
p, xiaohong, /users, POST
p, xiaohong, /index, GET
p, xiaohong, /home, GET

casbindemo.go

package main

import (
	"fmt"
	"github.com/casbin/casbin/v2"
	"log"
)

func assert(e *casbin.Enforcer, sub, obj, act string) {
	enforce, err := e.Enforce(sub, obj, act)
	if err != nil {
		fmt.Printf("enforce失败%s\n", err.Error())
	}
	if enforce {
		fmt.Printf("%s ASSERT_SUCCESS %s %s\n", sub, act, obj)
	} else {
		fmt.Printf("%s ASSERT_FAIL %s %s\n", sub, act, obj)
	}
}

func main() {
	e, err := casbin.NewEnforcer("./model.pml", "./policy.csv")
	if err != nil {
		log.Fatalf("NewEnforecer failed:%v\n", err)
	}

	assert(e, "xiaoming", "/hello", "GET")
	assert(e, "xiaoming", "/hello/go", "GET")
	assert(e, "xiaohong", "/hello", "POST")
	assert(e, "xiaohong", "/toto", "POST")
}

输出结果

xiaoming ASSERT_SUCCESS GET /hello
xiaoming ASSERT_SUCCESS GET /hello/go
xiaohong ASSERT_FAIL POST /hello
xiaohong ASSERT_FAIL POST /toto

Casbin配置文件详解

Request

代表请求。看我们上面的例子:

[request_definition]
r = sub, obj, act

代表一个请求有三个标准元素,请求主体,请求对象,请求操作

以用户 xiaohong用GET请求 /api/users接口为例:

请求主体就是 xiaohong

请求对象就是 /api/users

请求操作就是 GET

Policy和Policy_Rule

Policy 代表策略,它表示具体的权限定义的规则是什么

在policy.csv文件中定义的策略就是policy_rule。它和Policy是一一对应的。

例如我们上面的demo:

[policy_definition]
p = sub, obj, act

Matcher

有请求,有规则,那么请求是否匹配某个规则,则是matcher进行判断的,例如:

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

表示当m为true时 为验证通过 三个表达式都通过

Effect

Effect ⽤来判断如果⼀个请求满⾜了规则,是否需要同意请求。它的规则⽐较复杂⼀些。

[policy_effect]
e = some(where (p.eft == allow))

这里的some表示括号中的表达式个数大于等于1就行。 我们这句话的意思就是将request和所有policy比对完之后,所有policy的策略结果(p.eft)为allow的个数>=1,整个请求的策略就是true

访问控制模型

除了文档中提到的,casbin还支持多种访问控制模型

https://casbin.org/zh/docs/supported-models/

ACL访问控制

ACL是最早也是最基本的一种访问控制机制,它的原理非常简单:

每一项资源,都配有一个列表,这个列表记录的就是哪些用户可以对这项资源执行CRUD中的那些操作。当系统试图访问这项资源时,会首先检查这个列表中是否有关于当前用户的访问权限,从而确定当前用户可否执行相应的操作。总得来说,ACL是一种面向资源的访问控制模型,它的机制是围绕 资源 展开的。

上面的demo就是acl访问控制的例子

增加规则

e.AddPolicy("wangwu", "/users", "POST")
e.SavePolicy()

删除规则

e.RemovePolicy("wangwu", "/users", "POST")
e.SavePolicy()

RBAC访问控制

ACL模型在用户和资源都比较少的情况下没什么问题,但是用户和资源量一大,ACL就会变得异常繁琐

想象一下,每次新增一个用户,都要把他需要的权限重新设置一遍是多么地痛苦

RBAC(role-based-access-control)模型通过引入角色(role)这个中间层来解决这个问题

每个用户都属于一个角色,例如开发者、管理员、运维等,每个角色都有其特定的权限,权限的增加和删除都通过角色来进行

这样新增一个用户时,我们只需要给他指派一个角色,他就能拥有该角色的所有权限

修改角色的权限时,属于这个角色的用户权限就会相应的修改

mode.pml文件

[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

policy.csv

p, admin, /index, GET
p, admin, /home, GET
p, admin, /users, GET
p, admin, /users, POST
p, dev, /index, GET
p, dev, /home, GET
g, zhangsan, admin
g, wangwu, dev

有了角色之后,系统新增一个用户,只需要给这个用户分配角色

然后可以在角色管理中新增一个角色,然后设置角色的访问权限,可以访问哪些接口

在这个模式下,一个用户是可以有多个角色的

增加角色

e.AddPolicy("kuaiji", "/users", "GET")
e.SavePolicy()

增加用户-角色对应关系

e.AddRoleForUser("zhangsan", "kuaiji")
e.SavePolicy()

删除用户-角色对应关系

e.RemoveGroupingPolicy("zhangsan", "kuaiji")
e.SavePolicy()

删除角色

e.RemovePolicy("kuaiji", "/users", "GET")
e.SavePolicy()

gorm接入Casbin

其实基于上面的rbac,就可以做一个角色访问控制功能了

但是目前整个规则集是存储在文件中的

实际应用中肯定还是会把casbin的规则集放到数据库里面

go get github.com/casbin/gorm-adapter/v3

InitGorm

package core

import (
  "fmt"
  "github.com/sirupsen/logrus"
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
  "gorm.io/gorm/logger"
  "time"
)

func InitGorm() *gorm.DB {
  dsn := "root:root@tcp(127.0.0.1:3306)/rule_db?charset=utf8mb4&parseTime=True&loc=Local"

  var mysqlLogger logger.Interface
  db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
    Logger:                                   mysqlLogger,
    DisableForeignKeyConstraintWhenMigrating: true,
  })
  if err != nil {
    logrus.Error(fmt.Sprintf("[%s] mysql连接失败", dsn))
    panic(err)
  }
  sqlDB, _ := db.DB()
  sqlDB.SetMaxIdleConns(10)               // 最大空闲连接数
  sqlDB.SetMaxOpenConns(100)              // 最多可容纳
  sqlDB.SetConnMaxLifetime(time.Hour * 4) // 连接最大复用时间,不能超过mysql的wait_timeout
  return db
}

生成casbin表结构CasbinRule

gormadapter "github.com/casbin/gorm-adapter/v3"

global.DB.AutoMigrate(
  &gormadapter.CasbinRule{},
)

casbin连接gorm

global.DB = core.InitGorm()
a, _ := gormadapter.NewAdapterByDB(global.DB)
m, err := model.NewModelFromFile("./testdata/model.pml")
if err != nil {
  logrus.Error("字符串加载模型失败!", err)
  return
}
e, _ := casbin.NewCachedEnforcer(m, a)
e.SetExpireTime(60 * 60)
_ = e.LoadPolicy()

rbac模型的增删改查

e.AddPolicy("admin", "/api/users", "GET")
e.AddRoleForUser("zhangsan", "admin")
assert(e, "zhangsan", "/api/users", "GET")
e.RemoveGroupingPolicy("zhangsan", "admin")
e.RemovePolicy("admin", "/api/users", "GET")
assert(e, "zhangsan", "/api/users", "GET")
e.SavePolicy()
assert(e, "zhangsan", "/api/users", "GET")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值