2023-04-10
golang
00
请注意,本文编写于 653 天前,最后修改于 652 天前,其中某些信息可能已经过时。

目录

Casbin库实现权限控制
ACL
model文件
policy文件
RBAC模型
model文件
policy文件
多个RBAC
多层角色
RBAC domain
ABAC
模型存储

Casbin库实现权限控制

支持多种访问控制模型,如ACL/RBAC/ABAC等,可以实现灵活的访问权限控制

casbin将访问控制模型抽象到一个基于PERM(Policy,Effect,Request,Matchers)元模型的配置文件中

  • policy

测试或者是说规则的定义,定义了具体的规则

  • request

对访问请求的抽象,与e.Enforce()的参数一一对应

  • matcher

匹配器,请求与每个policy一一匹配,生成多个匹配结果

  • effect

对结果进行汇总,决定请求是允许还是拒绝

ACL

access-control-list 访问控制列表

显示定义了每个主体对每个资源的权限情况,未定义的就没有权限,还可以加入超级管理员,只需要修改匹配器即可

model文件

model.conf

[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文件

policy.csv

p,dajun,data1,read
p,lizi,data2,write

RBAC模型

ACL用户量一大就不得了,总不能每个用户都添加对应的策略文件吧

RBAC(role-based-access-control)通过引入角色来解决问题,给角色设置权限,而用户是属于角色,新增用户只需要赋予权限就可以了

model文件

model.conf

[role_definition]
g = _, _

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

policy文件

policy.csv

p,admin,data,read
p,admin,data,write
p,developer,data,read
g,dajun,admin
g,lizi,developer

多个RBAC

用户和资源都有角色

[role_definition]
g=_,_
g2=_,_

[matchers]
m = g(r.sub,p.sub) && g2(r.obj,p.obj) && r.act == p.act
p, admin, prod, read
p, admin, prod, write
p, admin, dev, read
p, admin, dev, write
p, developer, dev, read
p, developer, dev, write
p, developer, prod, read
g, dajun, admin
g, lizi, developer
g2, prod.data, prod
g2, dev.data, dev

多层角色

为角色定义所属角色,实现多层角色关系,例如高级开发者senior也属于开发者,拥有开发者的所有权限,然后再对senior定义自己所特有的权限

只需要修改对应的策略文件,将角色作为一个普通用户去赋予对应的父权限即可,这样就可以继承父角色的权限

RBAC domain

角色可以是全局的,也可以是特定domain(领域)tenant(租户),即分组

模型文件
[request_definition]
r = sub, dom, obj, act

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

[role_definition]
g = _,_,_

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

ABAC

前面的模型对于相对静态的权限管理比较有用,但是对于特殊、动态的需求就不合适了

例如不同时间段对数据实现不同的权限控制,就适合用ABAC模型完成

[request_definition]
r = sub,obj,act

[policy_definition]
p = sub,onj,act

[matchers]
m = r.sub.Hour >= 9 && r.sub.Hour < 18 || r.sub.Name == r.obj.Owner

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

模型存储

存储在文件里是十分不方便的,所以casbin实现在代码中动态初始化模型

例如字符串,或者调用方法添加,但是不常用

一般情况下,casbin支持第三方的存储方法,包括Mysql/MongoDB/Redis/Etcd等,还可以实现自己的存储

sql
CREATE DATABASE IF NOT EXISTS casbin;

USE casbin;

CREATE TABLE IF NOT EXISTS casbin_rule (
  p_type VARCHAR(100) NOT NULL,
  v0 VARCHAR(100),
  v1 VARCHAR(100),
  v2 VARCHAR(100),
  v3 VARCHAR(100),
  v4 VARCHAR(100),
  v5 VARCHAR(100)
);

INSERT INTO casbin_rule VALUES
('p', 'dajun', 'data1', 'read', '', '', ''),
('p', 'lizi', 'data2', 'write', '', '', '');
golang
package main

import (
  "fmt"

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

func check(e *casbin.Enforcer, sub, obj, act string) {
  ok, _ := e.Enforce(sub, obj, act)
  if ok {
    fmt.Printf("%s CAN %s %s\n", sub, act, obj)
  } else {
    fmt.Printf("%s CANNOT %s %s\n", sub, act, obj)
  }
}

func main() {
  a, _ := gormadapter.NewAdapter("mysql", "root:12345@tcp(127.0.0.1:3306)/")
  e, _ := casbin.NewEnforcer("./model.conf", a)

  check(e, "dajun", "data1", "read")
  check(e, "lizi", "data2", "write")
  check(e, "dajun", "data1", "write")
  check(e, "dajun", "data2", "read")
}

本文作者:Malyue

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!