当前位置: 首页 > 工具软件 > casbin > 使用案例 >

Casbin实现RBAC

席烨
2023-12-01

Casbin框架

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

官网:https://casbin.org/docs/zh-CN/rbac-with-domains-api

中文文档:https://casbin.org/docs/zh-CN/overview

RBAC API:https://casbin.org/docs/zh-CN/rbac-api

域内基于角色的访问控制 API:https://casbin.org/docs/zh-CN/rbac-with-domains-api

Casbin 是什么?

Casbin可以:

  1. 支持自定义请求的格式,默认的请求格式为{subject, object, action}
  2. 具有访问控制模型model和策略policy两个核心概念。
  3. 支持RBAC中的多层角色继承,不止主体可以有角色,资源也可以具有角色。
  4. 支持内置的超级用户 例如:rootadministrator。超级用户可以执行任何操作而无需显式的权限声明。
  5. 支持多种内置的操作符,如 keyMatch,方便对路径式的资源进行管理,如 /foo/bar 可以映射到 /foo*

Casbin不能:

  1. 身份认证 authentication(即验证用户的用户名、密码),casbin只负责访问控制。应该有其他专门的组件负责身份认证,然后由casbin进行访问控制,二者是相互配合的关系。
  2. 管理用户列表或角色列表。 Casbin认为由项目自身来管理用户、角色列表更为合适, 用户通常有他们的密码,但是Casbin的设计思想并不是把它作为一个存储密码的容器。 而是存储RBAC方案中用户和角色之间的映射关系。

Casbin配置文件(Model 文件)

RBAC

[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

支持域/租户的RBAC

[request_definition]
r = sub, dom, obj, act

[policy_definition]
p = sub, dom, obj, act

[role_definition]
g = _, _, _

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

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act

初始化Casbin

package casbin

import (
	"errors"
	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	"github.com/casbin/gorm-adapter/v3"
	"go.uber.org/zap"
	"yt.yin/core/global"
)

// InitCasbin
/**
 *  @Description: 初始化Casbin执行者(与gorm结合)
 *  @param DB Gorm连接池
 *  @param casbinConfPath casbin配置文件地址
 *  @return Enforcer casbin执行者
 *  @return err 错误
 */
func InitCasbin(casbinConfPath ...string) (err error) {
	// Gorm适配器
	adapter, err := gormadapter.NewAdapterByDB(global.DB)
	if err != nil {
		global.LOG.Error("创建Casbin Gorm适配器错误:", zap.Any("err", err))
		return  errors.New("Casbin Gorm适配器错误:" + err.Error())
	}
	global.LOG.Info("创建Casbin Gorm适配器成功")
	if len(casbinConfPath) > 0 {
		// 通过ORM新建一个执行者
		global.Enforcer, err = casbin.NewEnforcer(casbinConfPath[0], adapter)
		if err != nil {
			global.LOG.Error("新建Casbin执行者异常:", zap.Any("err", err))
			return  errors.New("新建Casbin执行者异常:" + err.Error())
		}
	} else {
		m, _ := 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 = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
			`)
		global.Enforcer, err = casbin.NewEnforcer(m, adapter)
		if err != nil {
			global.LOG.Error("新建Casbin执行者异常:", zap.Any("err", err))
			return  errors.New("新建Casbin执行者异常:" + err.Error())
		}
	}

	// 导入访问策略
	err = global.Enforcer.LoadPolicy()
	if err != nil {
		global.LOG.Error("导入访问策略异常:", zap.Any("err", err))
		return  errors.New("导入访问策略异常:" + err.Error())
	}
	return  nil
}
// 初始化casbin执行者
// Enforcer, casbinErr := casbin.InitCasbin("resources\\rbac_model.conf")
Enforcer, casbinErr := casbin.InitCasbin()
if casbinErr != nil {
	panic(casbinErr)
}
global.Enforcer = Enforcer

RBAC API

用户角色

为用户添加角色

e.AddRoleForUser("user", "role")

为用户添加多个角色

roles := []string{
    "role1",
    "role2",
    "role3",
    "role4",
    "role5",
	}
_, err = Enforcer.AddRolesForUser("user1", roles)
if err != nil {
    log.Fatalln("为用户批量添加角色失败")
}

删除用户角色

e.DeleteRoleForUser("user", "role")

删除用户的所有角色

e.DeleteRolesForUser("user")

获取用户角色

res, err := Enforcer.GetRolesForUser("user1")
if err != nil {
	log.Fatalln("获取用户角色失败")
} else {
	log.Println("用户角色:", res)
}

获取具有角色的用户

res := e.GetUsersForRole("role")

确定用户是否具有角色

res := e.HasRoleForUser("user", "role")

角色权限(API权限或策略)

添加API权限

_, err = Enforcer.AddPolicy("role1", "/api/5", "POST")
if err != nil {
	log.Fatalln("添加API权限(策略)失败")
} else {
	log.Println("添加API权限(策略)成功")
}

批量添加API权限

rules := [][]string{
		{"role1", "/api/1", "POST"},
		{"role2", "/api/1", "POST"},
		{"role3", "/api/1", "POST"},
		{"role1", "/api/2", "POST"},
		{"role1", "/api/3", "POST"},
		{"role1", "/api/4", "POST"},
		{"role1", "/api/5", "POST"},
	}

_, err = Enforcer.AddPolicies(rules)
if err != nil {
	log.Fatalln("批量添加API权限(策略)失败")
} else {
	log.Println("批量添加API权限(策略)成功")
}

批量删除API权限

_, err = Enforcer.DeletePermissionsForUser("role1")
if err != nil {
	log.Fatalln("批量删除API权限(策略)失败")
} else {
	log.Println("批量删除API权限(策略)成功")
}

API权限查询(利用API信息)

利用字段筛选器查询策略(授权规则)

answer := Enforcer.GetFilteredPolicy(0, "", "/api/4", "POST")
log.Println("answer:", answer)

查询角色的API权限列表

result := Enforcer.GetPermissionsForUser("role")
log.Println("策略:", result)

查询用户的API权限列表

result ,err= Enforcer.GetImplicitPermissionsForUser("user")
log.Println("策略:", result)

权限效验

sub := "user1"
obj := "/api/2"
act := "POST"
ok, err := Enforcer.Enforce(sub, obj, act)
if ok {
	fmt.Println("通过权限")
} else || err!=nil {
	fmt.Println("权限没有通过")
}

域内基于角色的访问控制 API(暂不需要)

在域内为用户添加角色

ok, err := e.AddRoleForUserInDomain("用户", "角色", "域")

如果用户已经拥有该角色,则返回false

在域内删除用户的角色

ok, err := e.DeleteRoleForUserInDomain("用户", "角色", "域")

如果用户没有任何角色,则返回false

在域内为角色批量添加API权限

rules := [][]string{
    { "role1", "domain1", "www.baidu.com", "GET"},
    { "role2", "domain1", "www.baidu.com", "GET"},
    { "role3", "domain1", "www.baidu.com", "GET"},
    { "role4", "domain1", "www.baidu.com", "GET"},
    { "role5", "domain1", "www.baidu.com", "GET"},
    { "role6", "domain1", "www.baidu.com", "GET"},
    { "role7", "domain1", "www.baidu.com", "GET"},
}
global.Enforcer.AddPolicies(rules)
 类似资料: