0%

基于RBAC角色的访问控制

前言

RBAC(Role-Based Access Control )基于角色的访问控制。

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

gorm-adapter使用这个库,Casbin可以从Gorm加载政策支持的数据库或保存政策。

理解casbin的使用

具体可以看这篇文章:Basic Role-Based HTTP Authorization in Go with Casbin(中文翻译为在 Go 语言中使用 casbin 实现基于角色的 HTTP 权限控制),具体demo我也加了详细注释。

这里有几个需要弄懂的:

模型文件的配置auth_model.conf

1
2
3
4
5
6
7
8
9
10
11
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

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

[matchers]
m = r.sub == p.sub && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")
  • Model CONF 至少应包含四个部分:[request_definition], [policy_definition], [policy_effect], [matchers]

  • 如果 model 使用 RBAC, 还需要添加[role_definition]部分。

  • sub, obj, act 表示经典三元组: 访问实体 (Subject),访问资源 (Object) 和访问方法 (Action)

  • 更具体的可以直接看官方文档

策略文件policy.csv

1
2
3
4
p, admin, /*, *
p, anonymous, /login, *
p, member, /logout, *
p, member, /member/*, *
  • admin 角色可以访问所有内容
  • member 角色可以访问以 /member/ 开头的路径和 logout 路径
  • 未认证用户可以登陆

gorm-adapter

在上个个例子中,策略文件就是一个简单的 csv 文件,描述了哪些角色可以访问哪些路径等。但在实际项目中策略文件一般都会存储在数据库,这时候就用到了gorm-adapter

直接看官方给出的demo

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
package main

import (
"github.com/casbin/casbin/v2"
gormadapter "github.com/casbin/gorm-adapter/v2"
_ "github.com/go-sql-driver/mysql"
)

func main() {

//初始化一个Gorm adapter 并在Casbin enforcer中使用它:
//Gorm adapter会使用一个名叫casbin的MySQL数据库
//如果不存在,将会自动创建
//或者通过 gormadapter.NewAdapterByDB(gormInstance)读取一个已经存在的数据库

a, _ := gormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/")
e, _ := casbin.NewEnforcer("examples/rbac_model.conf", a)

// Or you can use an existing DB "abc" like this:
// The adapter will use the table named "casbin_rule".
// If it doesn't exist, the adapter will create it automatically.
// a := gormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/abc", true)



e.LoadPolicy()//从数据库加载策略


e.Enforce("alice", "data1", "read")// 检查许可

// 更改策略
// e.AddPolicy(...)
// e.RemovePolicy(...)


e.SavePolicy()//保存策略
}

实际项目举例

rbac_model.conf模型文件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[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 && ParamsMatch(r.obj,p.obj) && r.act == p.act

qmplus.sql表的定义并通过sql往数据库添加数据

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
/*
Navicat Premium Data Transfer

Source Server : qmplus
Source Server Type : MySQL
Source Server Version : 50644
Source Host : localhost:3306
Source Schema : qmplus

Target Server Type : MySQL
Target Server Version : 50644
File Encoding : 65001

Date: 15/04/2020 17:48:50
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for casbin_rule
-- ----------------------------
DROP TABLE IF EXISTS `casbin_rule`;
CREATE TABLE `casbin_rule` (
`p_type` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v0` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v1` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v2` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v3` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v4` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`v5` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of casbin_rule
-- ----------------------------
INSERT INTO `casbin_rule` VALUES ('p', '8881', '/base/login', 'POST', '', '', '');
...

更新Casbin规则

1
2
3
4
5
6
7
8
func UpdateCasbinApi(oldPath string, newPath string, oldMethod string, newMethod string) error {
var cs []model.CasbinModel
err := global.GVA_DB.Table("casbin_rule").Where("v1 = ? AND v2 = ?", oldPath, oldMethod).Find(&cs).Updates(map[string]string{
"v1": newPath,
"v2": newMethod,
}).Error
return err
}

其中GVA_DB就是全局定义的gorm.DB实例

1
2
3
4
var (
GVA_DB *gorm.DB
...
)

资料

RBAC用户、角色、权限、组设计方案
casbin 基于角色的访问控制