​ 学习了之前的Casbin-model,就可以开始书写casbin的具体实现代码了,非常惭愧,昨天没有搓出博客,太懒了

思路

​ 在我认知范围内,casbin的具体实现思路是

casbin 和 gorm.adapter的依赖下载后

  1. 准备 model 和 adapter
  2. 通过上面两个东西创建一个enforce
  3. 提前加入 role+data1+action
  4. 其他需要做的就是 添加项目时 将 user与role绑定
  5. requre user 访问是否有相应的role policy
  6. 添加一些其他的有关policy的函数,查看,删除啥的

实践

​ 具体代码的呈现肯定不是直接按思路来的,不过我这里就按思路呈现一下代码。

  1. 准备 model 和 adapter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 准备model
const (
casModel = `
[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
`
)
m, err := model.NewModelFromString(casModel)

// 准备adapter,因为我这边是gorm数据库连接,所以直接使用的是gorm.adapter--会自动生成一个casbin_rule的数据库
// 1. 记得下载相应的依赖 2.其实直接用.cvs文件也能实现
adapter, _ := gormadapter.NewAdapter("mysql", "user:password@tcp(127.0.0.1:3307)/mysql", true)

官方文档里model还有两种写法:

1
2
// 直接从文件中读取model
e := casbin.NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 每一行中输入
// Initialize the model from Go code.
m := model.NewModel()
m.AddDef("r", "r", "sub, obj, act")
m.AddDef("p", "p", "sub, obj, act")
m.AddDef("g", "g", "_, _")
m.AddDef("e", "e", "some(where (p.eft == allow))")
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act")

// Load the policy rules from the .CSV file adapter.
// Replace it with your adapter to avoid using files.
a := fileadapter.NewAdapter("examples/rbac_policy.csv")

// Create the enforcer.
e := casbin.NewEnforcer(m, a)
  1. 通过上面两个东西创建一个enforce
1
2
// 组装厂   e *casbin.enforce
e, err := casbin.NewEnforcer(m, adapter)
  1. 提前加入 role+data1+action
1
2
3
4
5
// 加入基础的策略
func (e *MyEnforce) AddBasedPolicies() {
e.AddPolicy("user", "users", "read")
e.AddPolicy("user", "users", "write")
}
  1. 其他需要做的就是 添加项目时 将 user与role绑定
1
func (e *MyEnforce) LinkUserWithPolicy(name string) 
  1. requre user 访问是否有相应的role policy
1
2
3
4
5
func (e *MyEnforce) CheckUserPolicyForRead(name, data, action string) bool {
ok, _ := Enforce.Enforce(name, data, action)
return ok
}
// 如果存在返回ok
  1. 添加一些其他的有关policy的函数,查看,删除啥的
1
2
3
4
5
func (e *MyEnforce) UnLinkUserWithPolicy(name string) error {
_, err := e.RemoveGroupingPolicy(name, "user")
return err
}
// 删除操作......

整体代码呈现

1
2
3
4
5
6
7
8
9
// global/casbin/casbin.go

type MyEnforce struct {
*casbin.Enforcer
}
// 这个函数我也不知道有啥用,反正可以获得Enforce
func GetEnforce() *MyEnforce {
return Enforce
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// global/casbin/init.go
const (
casModel = `
[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
`
)
// 这边做了一层封装,还有Enforce全局变量的设定
// 其实我感觉没啥用。。。
var Enforce *MyEnforce

func Init() {
var err error
Enforce, err = createEnforcer()
if err != nil {
log.SugarLogger.Error(err)
return
}
err1 := Enforce.LoadPolicy()
if err1 != nil {
log.SugarLogger.Error(err)
return
}
Enforce.EnableAutoSave(true)
Enforce.AddBasedPolicies()
}

func createEnforcer() (*MyEnforce, error) {
m, err := model.NewModelFromString(casModel)
if err != nil {
return nil, err
}
adapter, err := gormadapter.NewAdapter("mysql", "user:password@tcp(127.0.0.1:3307)/mysql", true)
if err != nil {
return nil, err
}
e, err := casbin.NewEnforcer(m, adapter)
if err != nil {
return nil, err
}
return &MyEnforce{e}, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// global/casbin/util.go
package casbin

func (e *MyEnforce) AddBasedPolicies() {
e.AddPolicy("user", "users", "read")
e.AddPolicy("user", "users", "write")
}

func (e *MyEnforce) LinkUserWithPolicy(name string) error {
_, err := e.AddGroupingPolicy(name, "user")
return err
}

func (e *MyEnforce) UnLinkUserWithPolicy(name string) error {
_, err := e.RemoveGroupingPolicy(name, "user")
return err
}

func (e *MyEnforce) CheckUserPolicyForRead(name, data, action string) bool {
ok, _ := Enforce.Enforce(name, data, action)
return ok
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 路由实现中的操作,在新增项目或者注册用户的是否加上他的权限
// register.go
func Register(c *gin.Context) {
var user model.User
if err := c.ShouldBindJSON(&user); err != nil {
log.SugarLogger.Error(err)
errs2.Fail(c, errs2.INVALID_REQUEST.WithOrigin(err))
return
}

if len(user.Name) == 0 || len(user.Password) == 0 || len(user.Email) == 0 {
errs2.Fail(c, errs2.LOGIN_ERROR.WithTips("Username, password or email is required..."))
return
}

var v1 model.User
result := db.DB.Where("name = ?", user.Name).First(&v1)
if result.Error == nil {
errs2.Fail(c, errs2.LOGIN_ERROR.WithTips("姓名重复"))
}

if err := db.DB.Create(&user).Error; err != nil {
log.SugarLogger.Error(err)
errs2.Fail(c, errs2.DB_CRUD_ERROR.WithOrigin(err))
return
}
err := casbin.Enforce.LinkUserWithPolicy(user.Name)
if err != nil {
log.SugarLogger.Error(err)
errs2.Fail(c, errs2.SERVE_INTERNAL.WithOrigin(err))
return
}
errs2.Success(c, "注册成功")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 这里只试了一个操作,就是删除是否有权限
// delete.go
func Delete(c *gin.Context) {
password := c.PostForm("password")
payload, exists := c.Get("Payload")
if !exists {
errs2.Fail(c, errs2.UNTHORIZATION.WithTips("没有获取到payload"))
return
}
load := payload.(*jwt.MyCustomClaims)
ok := casbin.Enforce.CheckUserPolicyForRead(load.User, "users", "write")
if !ok {
errs2.Fail(c, errs2.UNTHORIZATION.WithTips("没有权限修改"))
return
}
var user model.User
db.DB.Where("name = ?", load.User).First(&user)
if user.Password != password {
fmt.Println("user.Password", user.Password)
fmt.Println(password)
errs2.Fail(c, errs2.INVALID_REQUEST.WithTips(password))
return
}

result := db.DB.Delete(&user)
if result.Error != nil {
log.SugarLogger.Error(result.Error)
errs2.Fail(c, errs2.DB_CRUD_ERROR.WithOrigin(result.Error))
return
}

errs2.Success(c, "注销成功")
}
1
2
3
4
5
6
7
8
9
10
11
//最后初始化

func Init() {
configs.Init()
db.Init()
casbin.Init()
for _, m := range module.Modules {
fmt.Println("Init Module: " + m.GetName())
m.Init()
}
}

总结

整体的代码实现参考了

  1. 官方文档
  2. 七淼up
  3. 老板的代码

总的来说,casbin就是一个工具,会用就行

如果不会用就找官网,官网的解释很详细,啥函数都一堆

casbin官网