概要

权限管理几乎是每个系统或者服务都会直接或者间接涉及的部分. 权限管理保障了资源(大部分时候就是数据)的安全, 权限管理一般都是和业务强关联, 每当有新的业务或者业务变化时, 不能将精力完全放在业务实现上, 权限的调整往往耗费大量的精力.

其实, 权限的本质没有那么复杂, 只是对访问的控制而已, 有一套完善的访问控制接口, 再加上简单的权限模型. 权限模型之所以能够简单, 就是因为权限管理本身并不复杂, 只是在和具体业务结合时, 出现了各种各样的访问控制场景, 才显得复杂.

PERM 模型

PERM(Policy, Effect, Request, Matchers)模型很简单, 但是反映了权限的本质 – 访问控制

  • Policy: 定义权限的规则
  • Effect: 定义组合了多个 Policy 之后的结果, allow/deny
  • Request: 访问请求, 也就是谁想操作什么
  • Matcher: 判断 Request 是否满足 Policy

casbin 权限库

casbin 使用了 PERM 模型来表达权限, 并且提供了简单直接的 API.

核心概念

model file

用来定义具体的权限模型, 目前支持的模型基本覆盖了常见的所有场景:

  1. ACL
  2. ACL with superuser
  3. ACL without users
  4. ACL without resources
  5. RBAC
  6. RBAC with resource roles
  7. RBAC with domains/tenants
  8. ABAC
  9. ……

model file 定义语法

casbin 是基于 PERM 的, 所有 model file 中主要就是定义 PERM 4 个部分.

  1. Request definition

    [request_definition]
    r = sub, obj, act

    分别表示 request 中的

    • accessing entity (Subject)
    • accessed resource (Object)
    • the access method (Action)
  2. Policy definition

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

    定义的每一行称为 policy rule, p, p2 是 policy rule 的名字. p2 定义的是 sub 所有的资源都能执行 act

  3. Policy effect

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

    上面表示有任意一条 policy rule 满足, 则最终结果为 allow

  4. Matchers

    [matchers]
    m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

    定义了 request 和 policy 匹配的方式, p.eft 是 allow 还是 deny, 就是基于此来决定的

  5. Role

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

    g, g2, g3 表示不同的 RBAC 体系, _, _ 表示用户和角色 _, _, _ 表示用户, 角色, 域(也就是租户)

policy file

定义具体的策略, 权限的检查就是基于定义的 model file 和 policy file 来完成的.

相对于 model file 定义规则, policy file 中定义的就是具体的内容.

RBAC 示例

定义 model file

[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

定义 policy file

p, superAdmin, project, read
p, superAdmin, project, write
p, admin, project, read
p, admin, project, write
p, admin, asse, read
p, admin, asse, write
p, zhuangjia, project, write
p, zhuangjia, asse, write
p, shangshang, project, read
p, shangshang, asse, read g, quyuan, admin
g, wenyin, zhuangjia

测试代码

package rbac

import (
"fmt"
"log" "github.com/casbin/casbin"
) func TestRBAC() {
e := casbin.NewEnforcer("rbac/rbac.conf", "rbac/rbac.csv") fmt.Printf("RBAC test start\n") // output for debug // superAdmin
if e.Enforce("superAdmin", "project", "read") {
log.Println("superAdmin can read project")
} else {
log.Fatal("ERROR: superAdmin can not read project")
} if e.Enforce("superAdmin", "project", "write") {
log.Println("superAdmin can write project")
} else {
log.Fatal("ERROR: superAdmin can not write project")
} // admin
if e.Enforce("quyuan", "project", "read") {
log.Println("quyuan can read project")
} else {
log.Fatal("ERROR: quyuan can not read project")
} if e.Enforce("quyuan", "project", "write") {
log.Println("quyuan can write project")
} else {
log.Fatal("ERROR: quyuan can not write project")
} if e.Enforce("quyuan", "asse", "read") {
log.Println("quyuan can read asse")
} else {
log.Fatal("ERROR: quyuan can not read asse")
} if e.Enforce("quyuan", "asse", "write") {
log.Println("quyuan can write asse")
} else {
log.Fatal("ERROR: quyuan can not write asse")
} // zhuangjia
if e.Enforce("wenyin", "project", "read") {
log.Fatal("ERROR: wenyin can read project")
} else {
log.Println("wenyin can not read project")
} if e.Enforce("wenyin", "project", "write") {
log.Println("wenyin can write project")
} else {
log.Fatal("ERROR: wenyin can not write project")
} if e.Enforce("wenyin", "asse", "read") {
log.Fatal("ERROR: wenyin can read asse")
} else {
log.Println("wenyin can not read asse")
} if e.Enforce("wenyin", "asse", "write") {
log.Println("wenyin can write asse")
} else {
log.Fatal("ERROR: wenyin can not write asse")
} // shangshang
if e.Enforce("shangshang", "project", "read") {
log.Println("shangshang can read project")
} else {
log.Fatal("ERROR: shangshang can not read project")
} if e.Enforce("shangshang", "project", "write") {
log.Fatal("ERROR: shangshang can write project")
} else {
log.Println("shangshang can not write project")
} if e.Enforce("shangshang", "asse", "read") {
log.Println("shangshang can read asse")
} else {
log.Fatal("ERROR: shangshang can not read asse")
} if e.Enforce("shangshang", "asse", "write") {
log.Fatal("ERROR: shangshang can write asse")
} else {
log.Println("shangshang can not write asse")
}
}

多租户示例

定义 model file

[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

定义 policy file

p, superAdmin, gy, project, read
p, superAdmin, gy, project, write
p, superAdmin, jn, project, read
p, superAdmin, jn, project, write
p, admin, gy, project, read
p, admin, gy, project, write
p, admin, jn, asse, read
p, admin, jn, asse, write
p, zhuangjia, jn, project, write
p, zhuangjia, gy, asse, write g, quyuan, admin, gy
g, quyuan, admin, jn
g, wenyin, zhuangjia, gy
g, shangshang, zhuangjia, jn

测试代码

package tenants

import (
"fmt"
"log" "github.com/casbin/casbin"
) // TestTenants test tenants
func TestTenants() {
e := casbin.NewEnforcer("tenants/tenants.conf", "tenants/tenants.csv") fmt.Printf("RBAC TENANTS test start\n") // output for debug // superAdmin
if e.Enforce("superAdmin", "gy", "project", "read") {
log.Println("superAdmin can read project in gy")
} else {
log.Fatal("ERROR: superAdmin can not read project in gy")
} if e.Enforce("superAdmin", "gy", "project", "write") {
log.Println("superAdmin can write project in gy")
} else {
log.Fatal("ERROR: superAdmin can not write project in gy")
} if e.Enforce("superAdmin", "jn", "project", "read") {
log.Println("superAdmin can read project in jn")
} else {
log.Fatal("ERROR: superAdmin can not read project in jn")
} if e.Enforce("superAdmin", "jn", "project", "write") {
log.Println("superAdmin can write project in jn")
} else {
log.Fatal("ERROR: superAdmin can not write project in jn")
} // admin
if e.Enforce("quyuan", "gy", "project", "read") {
log.Println("quyuan can read project in gy")
} else {
log.Fatal("ERROR: quyuan can not read project in gy")
} if e.Enforce("quyuan", "gy", "project", "write") {
log.Println("quyuan can write project in gy")
} else {
log.Fatal("ERROR: quyuan can not write project in gy")
} if e.Enforce("quyuan", "jn", "project", "read") {
log.Fatal("ERROR: quyuan can read project in jn")
} else {
log.Println("quyuan can not read project in jn")
} if e.Enforce("quyuan", "jn", "project", "write") {
log.Fatal("ERROR: quyuan can write project in jn")
} else {
log.Println("quyuan can not write project in jn")
} if e.Enforce("quyuan", "gy", "asse", "read") {
log.Fatal("ERROR: quyuan can read asse in gy")
} else {
log.Println("quyuan can not read asse in gy")
} if e.Enforce("quyuan", "gy", "asse", "write") {
log.Fatal("ERROR: quyuan can write asse in gy")
} else {
log.Println("quyuan can not write asse in gy")
} if e.Enforce("quyuan", "jn", "asse", "read") {
log.Println("quyuan can read asse in jn")
} else {
log.Fatal("ERROR: quyuan can not read asse in jn")
} if e.Enforce("quyuan", "jn", "asse", "write") {
log.Println("quyuan can write asse in jn")
} else {
log.Fatal("ERROR: quyuan can not write asse in jn")
} // wenyin
if e.Enforce("wenyin", "gy", "asse", "write") {
log.Println("wenyin can write asse in gy")
} else {
log.Fatal("ERROR: wenyin can not write asse in gy")
} if e.Enforce("wenyin", "jn", "asse", "write") {
log.Fatal("ERROR: wenyin can write asse in jn")
} else {
log.Println("wenyin can not write asse in jn")
} // shangshang
if e.Enforce("shangshang", "jn", "project", "write") {
log.Println("shangshang can write project in jn")
} else {
log.Fatal("ERROR: shangshang can not write project in jn")
} if e.Enforce("shangshang", "gy", "project", "write") {
log.Fatal("ERROR: shangshang can write project in gy")
} else {
log.Println("shangshang can not write project in gy")
}
}

总结

casbin 权限管理库比较简单, 易上手, 但是它的功能却不简单, 支持了目前主流的所有权限管理场景. 在使用上, model file 和 poclicy file 的定义也简单明了, 抽象出了权限管理最本质的东西.

将具体业务中的权限要求映射到 casbin 中 model file, 就可以借助 casbin 的 API, 快速的实现权限管理.

casbin-权限管理的更多相关文章

  1. Casbin权限模型

    权限框架casbin1.概述Casbin是一个强大的.高效的开源访问控制框架,其权限管理机制支持多种访问控制模型. Casbin支持以下编程语言: Casbin可以做到:支持自定义请求的格式,默认的请 ...

  2. Android权限管理之RxPermission解决Android 6.0 适配问题

    前言: 上篇重点学习了Android 6.0的运行时权限,今天还是围绕着Android 6.0权限适配来总结学习,这里主要介绍一下我们公司解决Android 6.0权限适配的方案:RxJava+RxP ...

  3. Android权限管理之Android 6.0运行时权限及解决办法

    前言: 今天还是围绕着最近面试的一个热门话题Android 6.0权限适配来总结学习,其实Android 6.0权限适配我们公司是在今年5月份才开始做,算是比较晚的吧,不过现在Android 6.0以 ...

  4. Android权限管理之Permission权限机制及使用

    前言: 最近突然喜欢上一句诗:"宠辱不惊,看庭前花开花落:去留无意,望天空云卷云舒." 哈哈~,这个和今天的主题无关,最近只要不学习总觉得生活中少了点什么,所以想着围绕着最近面试过 ...

  5. SpringMVC+Shiro权限管理【转】

    1.权限的简单描述 2.实例表结构及内容及POJO 3.Shiro-pom.xml 4.Shiro-web.xml 5.Shiro-MyShiro-权限认证,登录认证层 6.Shiro-applica ...

  6. Android6.0运行时权限管理

    自从Android6.0发布以来,在权限上做出了很大的变动,不再是之前的只要在manifest设置就可以任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒绝不该拥有的权限而导致的无法安装 ...

  7. Oracle 表空间和用户权限管理

    一. 表空间 Oracle数据库包含逻辑结构和物理结构. 数据库的物理结构指的是构成数据库的一组操作系统文件. 数据库的逻辑结构是指描述数据组织方式的一组逻辑概念以及它们之间的关系. 表空间是数据库逻 ...

  8. [Django]用户权限学习系列之权限管理界面实现

    本系列前三章: http://www.cnblogs.com/CQ-LQJ/p/5604331.htmlPermission权限基本操作指令 http://www.cnblogs.com/CQ-LQJ ...

  9. [Django]用户权限学习系列之设计自有权限管理系统设计思路

    若在阅读本片文章遇到权限操作问题,请查看本系列的前两章! http://www.cnblogs.com/CQ-LQJ/p/5609690.html和http://www.cnblogs.com/CQ- ...

  10. 我的MYSQL学习心得(十三) 权限管理

    我的MYSQL学习心得(十三) 权限管理 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) ...

随机推荐

  1. git tag本地删除以及远程删除

    假设存在tag:12345 git tag -d 12345 #删除本地记录 git push origin :refs/tags/12345 #删除远程记录 PS: 如果您觉得我的文章对您有帮助,可 ...

  2. helm 持久化部署ingres

    Ingress 是一种 Kubernetes 资源,也是将 Kubernetes 集群内服务暴露到外部的一种方式.本文将讲一讲如何用 Helm 在 Kubernetes 集群中部署 Ingress,并 ...

  3. SpringCloud的分布式配置及消息总线

    1.在搭建分布式配置时,我们大概看下分布式配置的流程 如图所示: 当一个系统中的配置文件发生改变的时候,我们需要重新启动该服务,才能使得新的配置文件生效,spring cloud config可以实现 ...

  4. grep 及正则表达式

    grpe 及正则表达式 文本查找的需要:grep,egrep,fgrepgrep: 根据模式,搜索文本,并将符合模式的文本行显示出来.Pattern : 文本字符以及正则表达式的元字符组合而成的匹配条 ...

  5. sdk和api的区别

    SDK SDK是Software Development Kit的缩写,中文意思是“软件开发工具包”.这是一个覆盖面相当广泛的名词,可以这么说:辅助开发某一类软件的相关文档.范例和工具的集合都可以叫做 ...

  6. 再谈AbstractQueuedSynchronizer1:独占模式

    关于AbstractQueuedSynchronizer JDK1.5之后引入了并发包java.util.concurrent,大大提高了Java程序的并发性能.关于java.util.concurr ...

  7. 0. VIM 系列 - 源码升级最新版本vim

    卸载原来的vim: $ sudo apt-get remove --purge vim $ suso apt-get clean 下载最新版本源码: $ git clone https://githu ...

  8. python maximum recursion depth exceeded 处理办法

    1.在执行命令 pyinstaller -F D:\py\programe\banksystem.py打包生成.exe文件时报错:python maximum recursion depth exce ...

  9. java面试基础(一)

    1.基本数据类型.封装类和运算操作(1)简述 & 和 && ,以及 | 和 || 的区别.———&和|是位运算符也是逻辑运算符,作为逻辑运算符时左右两边都会进行判断(不 ...

  10. python接口自动化(十)--post请求四种传送正文方式(详解)

    简介 post请求我在python接口自动化(八)--发送post请求的接口(详解)已经讲过一部分了,主要是发送一些较长的数据,还有就是数据比较安全等.我们要知道post请求四种传送正文方式首先需要先 ...