0
点赞
收藏
分享

微信扫一扫

选择适合户外篷房企业的企业云盘解决方案

独西楼Q 2023-10-06 阅读 40

文章目录

0. 背景

1. 准备工作

package main

import (
	"log"

	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"github.com/glebarez/sqlite"
	"gorm.io/gorm"
)

func main() {
	db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	a, err := gormadapter.NewAdapterByDB(db)
	if err != nil {
		panic("new gorm adapter error: " + err.Error())
	}

	m, err := model.NewModelFromString(`[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 = r.sub == p.sub && keyMatch2(r.obj,p.obj) && r.act == p.act`)
	if err != nil {
		panic("new model error: " + err.Error())
	}

	e, err := casbin.NewEnforcer(m, a)
	if err != nil {
		panic("new casbin enforcer error: " + err.Error())
	}

	e.LoadPolicy()
	// 添加策略
	ok, err := e.AddPolicy("admin", "/api/user", "GET")
	log.Println("add admin /api/user GET: ", ok, err)
	ok, err = e.AddGroupingPolicy("leo", "admin")
	log.Println("add leo to admin group: ", ok, err)
	e.SavePolicy()

	ok, err = e.Enforce("leo", "/api/user", "GET")
	log.Println("leo GET /api/user :", ok, err)
	ok, err = e.Enforce("leo", "/api/user", "DELETE")
	log.Println("leo DELETE /api/user :", ok, err)
}

type CasbinRule struct {
	ID    uint   `gorm:"primaryKey;autoIncrement"`
	Ptype string `gorm:"size:100"`
	V0    string `gorm:"size:100"`
	V1    string `gorm:"size:100"`
	V2    string `gorm:"size:100"`
	V3    string `gorm:"size:100"`
	V4    string `gorm:"size:100"`
	V5    string `gorm:"size:100"`
}

2. 权限配置以及增删改查

2.1 策略和组使用规范

ptypev0v1v2v3v4v5
padmin/api/userGET
padmin/api/userDELETE
puser/api/userGET
gleoadmin
gleo2user
package main

import (
	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"gorm.io/gorm"
)

type CasbinService struct {
	enforcer *casbin.Enforcer
	adapter  *gormadapter.Adapter
}

func NewCasbinService(db *gorm.DB) (*CasbinService, error) {
	a, err := gormadapter.NewAdapterByDB(db)
	if err != nil {
		return nil, err
	}
	m, err := model.NewModelFromString(`[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 = r.sub == p.sub && keyMatch2(r.obj,p.obj) && r.act == p.act`)
	if err != nil {
		return nil, err
	}
	e, err := casbin.NewEnforcer(m, a)
	if err != nil {
		return nil, err
	}
	return &CasbinService{adapter: a, enforcer: e}, nil
}

2.2 用户以及组关系的增删改查

2.2.1 获取所有用户以及关联的角色

[{
	"username": "leo",
	"roleNames": ["admin"]
}, {
	"username": "leo2",
	"roleNames": ["user"]
}]
type User struct {
	UserName  string
	RoleNames []string
}

// 获取所有用户以及关联的角色
func (c *CasbinService) GetUsers() (users []User) {
	p := c.enforcer.GetGroupingPolicy()
	usernameUser := make(map[string]*User, 0)
	for _, _p := range p {
		username, usergroup := _p[0], _p[1]
		if v, ok := usernameUser[username]; ok {
			usernameUser[username].RoleNames = append(v.RoleNames, usergroup)
		} else {
			usernameUser[username] = &User{UserName: username, RoleNames: []string{usergroup}}
		}
	}
	for _, v := range usernameUser {
		users = append(users, *v)
	}
	return
}

2.2.2 角色组中添加用户

// 角色组中添加用户, 没有组默认创建
func (c *CasbinService) UpdateUserRole(username, rolename string) error {
	_, err := c.enforcer.AddGroupingPolicy(username, rolename)
	return err
}

2.2.3 角色组中删除用户

// 角色组中删除用户
func (c *CasbinService) DeleteUserRole(username, rolename string) error {
	_, err := c.enforcer.RemoveGroupingPolicy(username, rolename)
	return err
}

2.3 角色组权限的增删改查

2.3.1 获取所有角色组权限

[{
	"roleName": "admin",
	"url": "/api/user",
	"method": "DELETE"
}, {
	"roleName": "admin",
	"url": "/api/user",
	"method": "GET"
}, {
	"roleName": "user",
	"url": "/api/user",
	"method": "GET"
}]
```go
// (RoleName, Url, Method) 对应于 `CasbinRule` 表中的 (v0, v1, v2)
type RolePolicy struct {
	RoleName string `gorm:"column:v0"`
	Url      string `gorm:"column:v1"`
	Method   string `gorm:"column:v2"`
}

// 获取所有角色组权限
func (c *CasbinService) GetRolePolicy() (roles []RolePolicy, err error) {
	err = c.adapter.GetDb().Model(&gormadapter.CasbinRule{}).Where("ptype = 'p'").Find(&roles).Error
	if err != nil {
		return nil, err
	}
	return
}

2.3.2 创建角色组权限

// 创建角色组权限, 已有的会忽略
func (c *CasbinService) CreateRolePolicy(r RolePolicy) error {
	// 不直接操作数据库,利用enforcer简化操作
	err := c.enforcer.LoadPolicy()
	if err != nil {
		return err
	}
	_, err = c.enforcer.AddPolicy(r.RoleName, r.Url, r.Method)
	if err != nil {
		return err
	}
	return c.enforcer.SavePolicy()
}

2.3.3 修改角色组权限

// 修改角色组权限
func (c *CasbinService) UpdateRolePolicy(old, new RolePolicy) error {
	_, err := c.enforcer.UpdatePolicy([]string{old.RoleName, old.Url, old.Method},
		[]string{new.RoleName, new.Url, new.Method})
	if err != nil {
		return err
	}
	return c.enforcer.SavePolicy()
}

2.3.4 删除角色组权限

// 删除角色组权限
func (c *CasbinService) DeleteRolePolicy(r RolePolicy) error {
	_, err := c.enforcer.RemovePolicy(r.RoleName, r.Url, r.Method)
	if err != nil {
		return err
	}
	return c.enforcer.SavePolicy()
}

3. 测试以及完整代码

3.1 casbin_service.go

package main

import (
	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"gorm.io/gorm"
)

/*
按如下约定:
  1. 所有策略只针对角色组设置
  2. 用户关联到组(一个用户可以有多个组)
+-------+-------+-----------+--------+----+----+----+
| ptype | v0    | v1        | v2     | v3 | v4 | v5 |
+-------+-------+-----------+--------+----+----+----+
| p     | admin | /api/user | GET    |    |    |    |
+-------+-------+-----------+--------+----+----+----+
| p     | admin | /api/user | DELETE |    |    |    |
+-------+-------+-----------+--------+----+----+----+
| p     | user  | /api/user | GET    |    |    |    |
+-------+-------+-----------+--------+----+----+----+
| ...   | ...   | ...       |        |    |    |    |
+-------+-------+-----------+--------+----+----+----+
| g     | leo   | admin     |        |    |    |    |
+-------+-------+-----------+--------+----+----+----+
| g     | leo2  | admin     |        |    |    |    |
+-------+-------+-----------+--------+----+----+----+
*/
type CasbinService struct {
	enforcer *casbin.Enforcer
	adapter  *gormadapter.Adapter
}

func NewCasbinService(db *gorm.DB) (*CasbinService, error) {
	a, err := gormadapter.NewAdapterByDB(db)
	if err != nil {
		return nil, err
	}
	m, err := model.NewModelFromString(`[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 = r.sub == p.sub && keyMatch2(r.obj,p.obj) && r.act == p.act`)
	if err != nil {
		return nil, err
	}
	e, err := casbin.NewEnforcer(m, a)
	if err != nil {
		return nil, err
	}
	return &CasbinService{adapter: a, enforcer: e}, nil
}

// (RoleName, Url, Method) 对应于 `CasbinRule` 表中的 (v0, v1, v2)
type RolePolicy struct {
	RoleName string `gorm:"column:v0"`
	Url      string `gorm:"column:v1"`
	Method   string `gorm:"column:v2"`
}

// 获取所有角色组权限
func (c *CasbinService) GetRolePolicy() (roles []RolePolicy, err error) {
	err = c.adapter.GetDb().Model(&gormadapter.CasbinRule{}).Where("ptype = 'p'").Find(&roles).Error
	if err != nil {
		return nil, err
	}
	return
}

// 创建角色组权限, 已有的会忽略
func (c *CasbinService) CreateRolePolicy(r RolePolicy) error {
	// 不直接操作数据库,利用enforcer简化操作
	err := c.enforcer.LoadPolicy()
	if err != nil {
		return err
	}
	_, err = c.enforcer.AddPolicy(r.RoleName, r.Url, r.Method)
	if err != nil {
		return err
	}
	return c.enforcer.SavePolicy()
}

// 修改角色组权限
func (c *CasbinService) UpdateRolePolicy(old, new RolePolicy) error {
	_, err := c.enforcer.UpdatePolicy([]string{old.RoleName, old.Url, old.Method},
		[]string{new.RoleName, new.Url, new.Method})
	if err != nil {
		return err
	}
	return c.enforcer.SavePolicy()
}

// 删除角色组权限
func (c *CasbinService) DeleteRolePolicy(r RolePolicy) error {
	_, err := c.enforcer.RemovePolicy(r.RoleName, r.Url, r.Method)
	if err != nil {
		return err
	}
	return c.enforcer.SavePolicy()
}

type User struct {
	UserName  string
	RoleNames []string
}

// 获取所有用户以及关联的角色
func (c *CasbinService) GetUsers() (users []User) {
	p := c.enforcer.GetGroupingPolicy()
	usernameUser := make(map[string]*User, 0)
	for _, _p := range p {
		username, usergroup := _p[0], _p[1]
		if v, ok := usernameUser[username]; ok {
			usernameUser[username].RoleNames = append(v.RoleNames, usergroup)
		} else {
			usernameUser[username] = &User{UserName: username, RoleNames: []string{usergroup}}
		}
	}
	for _, v := range usernameUser {
		users = append(users, *v)
	}
	return
}

// 角色组中添加用户, 没有组默认创建
func (c *CasbinService) UpdateUserRole(username, rolename string) error {
	_, err := c.enforcer.AddGroupingPolicy(username, rolename)
	return err
}

// 角色组中删除用户
func (c *CasbinService) DeleteUserRole(username, rolename string) error {
	_, err := c.enforcer.RemoveGroupingPolicy(username, rolename)
	return err
}

3.2 casbin_service_test.go

package main

import (
	"testing"

	"github.com/glebarez/sqlite"
	"gorm.io/gorm"
)

func TestCasbinService(t *testing.T) {
	db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
	s, err := NewCasbinService(db)
	if err != nil {
		t.Fatalf("new service error: %v", err)
	}

	// 创建个用户,分别关联到`admin`和`user`组, `leo2`既是`admin`组又是`user`组
	t.Logf("create user: leo with group: admin result: %v", s.UpdateUserRole("leo", "admin"))
	t.Logf("create user: leo with group: admin result: %v", s.UpdateUserRole("leo2", "admin"))
	t.Logf("create user: leo with group: admin result: %v", s.UpdateUserRole("leo2", "user"))
	t.Log()
	t.Logf("users is: %v\n", s.GetUsers())

	// 针对`admin`和`user`组创建三条策略
	t.Log("create admin /api/user GET: ", s.CreateRolePolicy(RolePolicy{RoleName: "admin", Url: "/api/user", Method: "GET"}))
	t.Log("create admin /api/user DELETE: ", s.CreateRolePolicy(RolePolicy{RoleName: "admin", Url: "/api/user", Method: "DELETE"}))
	t.Log("create user /api/user GET: ", s.CreateRolePolicy(RolePolicy{RoleName: "user", Url: "/api/user", Method: "GET"}))
	t.Log("all policy is: ")
	t.Log(s.GetRolePolicy())

	t.Log("delete admin /api/user GET", s.DeleteRolePolicy(RolePolicy{RoleName: "admin", Url: "/api/user", Method: "GET"}))
}


3.3测试结果

在这里插入图片描述
在这里插入图片描述

4. 结语

举报

相关推荐

0 条评论