Zhong__一文通透Casbin

时间:2021.12.06

环境:Windows

目的:Casbin简介与使用 希望对大家有帮助

说明:以官方文档为基础来讲解与拓展详解,并最终帮助大家在项目中使用!本文持续更新丰富内容  。。。

作者:Zhong QQ交流群:121160124 欢迎加入!

关于Casbin

官方网站:Overview · Casbin 

官方qq交流群:546057381

话在前面

满招损 谦受益

失之毫厘 差之千里

业精于勤荒于嬉 行成于思毁于随

三人行必有我师焉

择其善者而从之 其不善者而改之

海纳百川 有容乃大

壁立千仞 无欲则刚

合抱之木 生于毫末

九层之台 起于累土

千里之行 始于足下

        大家好!简单介绍下我自己,我是  谁并不重要,重要的是你想了解和掌握Casbin!进入正题!

        我们假设你对Go语言有一定了解,不了解也无太多所谓,重点是Casbin的设计思想,Casbin努力成为与编程语言无关的,解耦的权限框架!致力于多种语言一致体验,直白来说,就是一套规则框架,在各种编程语言中稍微改动就可以与业务系统结合使用,使其成为与语言、语言框架无关且通用的权限管理系统。

本文内容比较多  请耐心阅读!!!绝对是最详细最干货的文章,没有之一!!!网上的关于Casbin的文章大多都读过,没发现很全面的。。。

简介

Casbin 是什么?

我们先来看看官方对它的定义:

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

Casbin 可以:

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

Casbin 不能:

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

我们可以理解为Casbin做的是3A(认证、授权、审计)之中的授权这一步,也是主旨!

Casbin支持的编程语言

 在不同语言中支持的特性

特性

Go

Java

Node.js

PHP

Python

C#

Delphi

Rust

C++

Lua

Dart

Exilir

具体实施

RBAC

ABAC

Scaling ABAC (eval())

Adapter

Management API

RBAC API

Batch API

Filtered Adapter

Watcher

Role Manager

Multi-Threading

matcher中的‘in‘语法

我们一直致力于让 Casbin 在不同的编程语言中拥有相同的特性。 但是现实总是不完美的。 上方的表格展示了当前的进度。 Watcher 和 Role Manager 的 ✅ 仅代表 Casbin 对该编程语言有接口, 是否实现了 watcher 或 role manager 接口则是另一回事了。

tips:特性支持持续更新中 ... ...

理解与使用

我们以Go为主、Python为辅通过demo来理解和使用Casbin,更多语言支持请访问官网

安装

golang

go get github.com/casbin/casbin/v2

python

pip install casbin

 在线工具

古人云 工欲善其事 必先利其器

官方推出的在线认证库工具 对于调试和理解很有用 建议多使用

方便体验定义Model、Policy、Request,验证并获取结果,得到你想要的的Model定义

在线工具:Casbin · An authorization library that supports access control models like ACL, RBAC, ABAC for Golang, Java, C/C++, Node.js, Javascript, PHP, Laravel, Python, .NET (C#), Delphi, Rust, Ruby, Swift (Objective-C), Lua (OpenResty), Dart (Flutter) and ElixirAn authorization library that supports access control models like ACL, RBAC, ABAC for Golang, Java, C/C++, Node.js, Javascript, PHP, Laravel, Python, .NET (C#), Delphi, Rust, Ruby, Swift (Objective-C), Lua (OpenResty), Dart (Flutter) and Elixiricon-default.png?t=N7T8https://casbin.org/en/editor

基础demo

先不着急深入理解它的各种概念,先来通过最基础的demo体验一下

我们创建一个文件夹随便什么名如demo,在demo里面创建三个文件main.go/model.conf/policy.csv,内容分别如下

main.go

package main

import (
	"fmt"
	"github.com/casbin/casbin/v2"
	"log"
)
func main() {
	e, err := casbin.NewEnforcer("model.conf", "policy.csv")
	if err != nil {
		log.Fatalf("error: enforcer: %s", err)
	}

	sub := "alice" // 想要访问资源的用户。
	obj := "data1" // 将被访问的资源。
	act := "read" // 用户对资源执行的操作。

	ok, err := e.Enforce(sub, obj, act)
	if err != nil {
		// 处理err
		fmt.Println(err.Error())
	}

	if ok == true {
		// 允许 do next ...
		fmt.Printf("%s cat %s %s\n", sub, act, obj)
	} else {
		// 拒绝请求,抛出异常
		fmt.Printf("%s cat't %s %s\n", sub, act, obj)
	}
}

model.conf

[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 && r.obj == p.obj && r.act == p.act

policy.csv

p, alice, data1, read
p, alice, data2, write

 运行 go run main.go  输出下面的结果

alice cat read data1

如果将main.go中的obj := "data1"改为obj := "data2"那么将输出

alice cat't read data2

        上面字面上的意思是alice可以read data1,不可以read data2,因为我们只给她write data2的权限!相信在这里肯定有人会感到迷惑,不明白什么意思,主要是因为和我们实际开发业务基于rustful的GET/POST/PUT/DELETE不一样!那么如下就明了

policy.csv

允许alice GET请求url /index查看主页

允许alice GET、POST url /user来获取用户信息和新增用户

p, alice, /index, GET
p, alice, /user, GET
p, alice, /user, POST

main.go

	sub := "alice" // 想要访问资源的用户。
	obj := "/index" // 将被访问的资源。
	act := "GET" // 用户对资源执行的操作。

接着上面的说,alice我们视为一个请求主体这儿就是一个用户,data1是资源也就是访问操作的数据,read是一个动作,代表请求主体对资源的操作!简单来说就是谁可以对资源做什么,不可以对资源做什么!这种说法可以视为一种规则约束,那么将这种规则抽象出来就是上面的model.conf文件,也称为访问控制模型。规则有了,就要有实体配合才能发挥作用,policy.csv定义的就是具体的实例,就像盖一栋楼,首先要有设计人员设计施工图纸,有了图纸按照指引该建设什么,该避免什么就可以完成施工建造出具体的大楼!因此,在Casbin的架构里,核心就是model(模型)和policy(策略)!其它都是围绕它的具体实现和控制!理解了model与policy也就理解了Casbin,其中重点、难点就是model里面的概念与如何定义!

它是怎么工作的呢?

接下来的话对理解权限很重要

想想在平时的开发中尤其是前后端分离的开发模式,前端往往根据后端提供的API(应用程序接口)来访问服务器资源,这些API在前端来讲就是URI(统一资源定位符),也就如你在访问百度时浏览器地址栏输入的url:https://baidu.com,每一个url代表了服务器上的某个资源。例如,我们想要获取系统里所有的用户,输入127.0.0.1:8000/users,获取id为100的这个用户输入127.0.0.1:8000/users/100,后端程序根据url路由来调用对应的处理方法检查当前用户是否已登录,是否有权限访问这个url,如果有权限那么查询MySQL数据库等等一系列操作后最终将目标数据返回给前端展示,那么就完成了一次前后端的请求交互!url不同,对应的资源数据也就会不同!所以,从某种角度来说,对权限的控制其实就是对url的控制!一个用户有多少权限取决于她有多少个url的访问权限!

Casbin通过model定义规则约束,policy实例化model为一条条具体的规则来控制权限

Model

下面是一个典型的ACL控制模型

[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 && r.obj == p.obj && r.act == p.act

在 Casbin 中, 访问控制模型被抽象为基于 PERM (Policy, Effect, Request, Matcher) 的一个文件(model.conf)。 因此,切换或升级项目的授权机制与修改配置一样简单。 您可以通过组合可用的模型来定制您自己的访问控制模型。 例如,您可以在一个model中结合RBAC角色和ABAC属性,并共享一组policy规则。

PERM模式由四个基础(请求、政策、效果、匹配)组成,描述了资源与用户之间的关系。

Request(请求)

官网解释:

定义请求参数。基本请求是一个元组对象,至少需要主题(访问实体)、对象(访问资源) 和动作(访问方式)

例如,一个请求可能长这样: r={sub,obj,act}

它实际上定义了我们应该提供访问控制匹配功能的参数名称和顺序。




个人理解:

对应上面模型的request_definition部分 如下

[request_definition]
r = sub, obj, act

这条“规则”指明一次请求至少需要提供三个参数:请求主体、要访问的资源和请求方式,即前端访问API时提供当前请求的用户、要访问的url和动作(GET/POST...)

例如:alice /user/100/info GET  alice用户的id为100 她要查询自己的个人信息


Policy(策略)

官网解释:

定义访问策略模式。事实上,它是在政策规则文件中定义字段的名称和顺序。

例如: p={sub, obj, act} 或 p={sub, obj, act, eft}

注:如果未定义eft (policy result),则策略文件中的结果字段将不会被读取, 和匹配的策略结果将默认被允许。




个人理解:

对应上面模型的policy_definition部分 如下

[policy_definition]
p = sub, obj, act

这条“规则”指明policy的格式应至少有三个参数:访问主体、访问对象和访问方式,与request_definition中的元素一一对应,不过这些实体一般是存在于数据库中的如MySQL默认生成的casbin数据库里的casbin_rule表,这就很好理解了,请求的时候(request)给了三个必要参数,拿着这三个参数来检索policys看是否有之对应的,也就是下面Matcher定义的规则



Matcher(匹配器)

匹配请求和政策的规则。

例如: m = r.sub == p.sub && r.act == p.act && r.obj == p.obj 这个简单和常见的匹配规则意味着如果请求的参数(访问实体,访问资源和访问方式)匹配, 如果可以在策略中找到资源和方法,那么策略结果(p.eft)便会返回。 策略的结果将保存在 p.eft 中。






Effect(效果)

它可以被理解为一种模型,在这种模型中,对匹配结果再次作出逻辑组合判断。

例如: e = some (where (p.eft == allow))

这句话意味着,如果匹配的策略结果有一些是允许的,那么最终结果为真。大白话来说就是请求一个url的结果无非就是允许和拒绝两种情况,如果查询到允许请求这个url,那么就通过(True),否则就拒绝(False)。

Policy

其实如果明白了model的话policy还是很容易理解的,无非是对应model规则的策略实体。

Storage(存储)

model和policy均有不同的存储方式

Model Storage

不同于policy,model只能用于加载而不能存储,为什么呢?只是因为model是一个文件吗?不是的,因为我们认为 model 不是动态组件,不应该在运行时进行修改,所以我们没有实现一个 API 来将 model 保存到存储中。想想一下,用于建筑高楼大厦的图纸在开工之后会改来改去吗?肯定不会的一般都是设计好之后开始建造的,除非有必要!

好消息是,官方提供了三种等效的方法来静态或动态地加载模型:

从 .CONF 文件中加载 model

当你向 Casbin 团队寻求帮助时,他们会给你这个 Casbin 最常用的方法,此方法对于初学者来说很容易理解并且便于分享。

从代码加载 model

模型可以从代码中动态初始化,不需要使用 .CONF

从字符串加载的 model

或者也可以从多行字符串加载整个模型文本。这种方法的优点是您不需要维护模型文件。

具体方法参照官网实例,不再赘述!

上面说到model不会经常变化所以不能存储,那么policy呢?答案是肯定需要存储!

Policy Storage

在Casbin中,策略存储作为适配器实现。

Adapters(适配器)

在Casbin中,policy(策略)存储作为adapter(Casbin的中间件) 实现。 policy理论上会经常变化,Casbin用户可以使用adapter从存储中加载策略规则 (aka LoadPolicy()) 或者将策略规则保存到其中 (aka SavePolicy())。 demo中用于演示我们从一个csv文件读取policy,但在实际项目中,我们更多使用数据库存储,如MySQL、MongoDB等,使用数据库更方便管理,对于巨量策略条目性能也更高!Casbin官方提供了完整的适配器列表供选择,包含了各种主流编程语言以及各种主流数据库、云及文件如csv等的支持,有官方的也有第三方的具体请参照官网!

我们以Go语言、MySQL数据库和gorm orm库为例

安装gorm-adapter

go get github.com/casbin/gorm-adapter/v3

代码如下 

package main

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

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

	ok, err := e.Enforce("alice", "data1", "read")
	if err != nil {
		fmt.Println(err.Error())
	}

	fmt.Println(ok)
}

 gormadapter.NewAdapter("mysql", "root:123456@tcp(127.0.0.1:3306)/your_database")  如果/your_database没有指定数据库那么将默认创建名为casbin的数据库,并且创建一张表名为casbin_rule,字段如下

 插入一条数据

运行go run main.go 将输出 true 意味着用户alice拥有read资源data1的权限,其它权限均无!

以上实例我们创建了gorm类型adapter,它使用MySQL作为policy存储容器,并使用默认生成的数据库casbin中的casbin_rule表存储具体的policy,返回*Adapter与err对象,然后调用NewEnforcer方法加载模型文件model.conf与适配器a,对alice鉴权。在此,我们需要知道并记住的是,Casbin默认将policy(策略)加载到内存中,如果改变了存储容器内的策略数据需要执行LoadPolicy()方法重载策略到内存才能生效!方便的是,我们在官方提供的API中不需要手动去调用,这些方法底层已实现,除非特别说明!由此指出,如果我们自己实现某些会改变策略方法的话需要实现这个方法,否则就要手动调用或重启,常见的问题有程序在运行时,手动往数据表插入一条策略去测试并未生效!查询等不涉及改变数据表数据的操作不需要有此操作!

疑问与思考

古德,你已经迫不及待的把Casbin部署在公司项目中,为了谨慎起见,你只是在两台服务器部署了你的项目(也算是最小的集群了),并给你的同事如花小姐姐建立了账户分配了角色,邀请她体验和测试。but,what?正当你满心欢喜的期待时,阿花却告诉你:sorry!你一脸茫然,于是自己也测试了一下,发现了问题:请求一次正常,下一次请求401,再下一次又是正常访问,如此循环反复,这是为什么呢?于是你陷入了思考......

既然策略加载在内存 如何在分布式集群部署项目中保持策略的同步呢?答案是Watcher

Watchers(观察者)

何为观察者?

        我们造 古时候通讯没有现在发达方便 但前人有智慧啊!他们设置了望楼并发明了各种各样的旗语,用来主动发现目光所及范围内的情况或者和其它望台、其他人进行“交流”,来达到第一时间“共享”消息或者发布指令的目的。

为什么需要观察者?

        通过前面的介绍我们知道,策略默认是从文件或数据库读取之后加载到内存中的,只有在创建、更新、删除等(没有等?)操作会改变策略的时候触发LoadPolicy()来重载策略到当前服务器的内存,当我们在多台服务器以负载均衡的方式部署项目时,在一次请求中“改变”了策略,那么处理这条请求的服务器会重载策略到当前服务器的内存,但是其它服务器不知道,因为没有“人”通知它,所以它们自顾自乐呵乐呵的期待着下一个用户的请求。比如,你和一群小伙伴相约去公园踏春赏景,精心装扮一番后去见你的女神,结果发现她没来,只有小红说给她发了信息说不来了,而小红以为大家都收到消息了没有再通知其他人,那么如果女神群发消息的话大家就可以都知道了!所以,上面的需求就需要一个机制来完成策略同步(当策略有变化时,所有服务端应同步最新策略保持一致),于是乎,Watcher应运而生!

tips:单机不需要的哦!

Dispatchers

Role Managers(角色管理)

Middlewares(中间件)

开源项目推荐

推荐几个不错的集成了Casbin鉴权的开源项目 出场顺序不排名

gin-vue-admin

github:https://github.com/flipped-aurora/gin-vue-admin

项目简介

基于vite+vue3+gin搭建的开发基础平台,集成jwt鉴权,权限管理,动态路由,分页封装,多点登录拦截,资源权限,上传下载,代码生成器,表单生成器等开发必备功能,五分钟一套CURD前后端代码。

go-admin

github:https://github.com/go-admin-team/go-admin

项目简介

gin-admin

github:https://github.com/LyricTian/gin-admin

项目简介

go-admin

github:https://github.com/GoAdminGroup/go-admin/

项目简介

A golang framework helps gopher to build a data visualization and admin panel in ten minutes

GoAdmin是一个基于 golang 面向生产的数据可视化管理平台搭建框架,可以让你使用简短的代码在极短时间内搭建起一个管理后台。

ginskeleton-admin2

GitHub:  qifengzhang007/ginskeleton-admin2-backend: ginskeleton-admin2 后端子项目

项目简介

admin 系统集成界面, 定位快速开发业务方向, 可以在不需要修改一行代码的情况下,快速进入业务开发模式.

ferry

github:https://github.com/lanyulei/ferry

项目简介

本系统是集工单统计、任务钩子、权限管理、灵活配置流程与模版等等于一身的开源工单系统,当然也可以称之为工作流引擎。 致力于减少跨部门之间的沟通,自动任务的执行,提升工作效率与工作质量,减少不必要的工作量与人为出错率。

tips:以上项目是笔者发现的几个不错的开源项目,项目简介引用项目本身介绍,对于入门和理解使用Casbin在项目中的应用有一定的借鉴作用。当然还有很多优秀的项目等待笔者和你的发现!

生产中实例解析

上面列举了几个集成casbin的开源项目 用法虽有所差异 但总体思路基本是一致的 接下来以 gin-vue-admin 为例 浅析casbin在项目中的一般用法

gin-vue-admin前端使用vue(3)框架,后端使用golang语言的gin框架,使用MySQL数据库存储数据。  它是典型的RBAC(基于角色的权限控制)模型 以角色为单位(sub)  将资源(url 即casbin里的策略)独立出来在web页面统一管理 如图

然后在角色管理中分配角色拥有哪些api(对应url)  如图

分配完成后程序会更新casbin_rule表里的数据  并重载策略到内存

在service/system/sys_casbin.go文件指定模型(model) 如下

[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

在casbin_rule表存储策略 数据格式内容举例如下所示

idptypev0v1v2
1p888/user/changePasswordPOST

角色是访问资源的实体(sub)  在此项目中使用数字如888表示 当然可以用具名的名称如admin表示 这个不是重点 以上表示有一条访问策略(p)  sub实体即角色(v0)为888的可以使用POST(v2)访问资源(v1)/user/changePassword  

路由配置中将路由分为了不需要鉴权的路由组(PublicGroup)和需要鉴权的路由组(PrivateGroup) 

PrivateGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix)
PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())

        不需要鉴权很好理解就是公共接口资源如登录接口  不需要认证你是谁  谁都可以访问  需要鉴权的接口如用户信息、角色信息、菜单信息等是需要已经登录并且有权限的人如管理员才可以访问 

         在需要鉴权的路由组中  首先通过中间件JWTAuth进行认证获取用户、角色信息  然后通过中间件CasbinHandler查验上一步获取到的角色在MySQL casbin_rule表中是否有对应的策略  并且根据model定义的规则匹配策略  根据匹配的结果决定是否允许访问  在这一过程中 jwt执行的是认证  casbin执行的是访问控制  也就是开始所说的 casbin不做身份认证 authentication(即验证用户的用户名、密码),casbin只负责访问控制。

引申

Casdoor

casdooricon-default.png?t=N7T8https://casdoor.org/zh/

支持 OAuth 2.0、OIDC 和 SAML 的 UI 优先集中式身份验证/单点登录 (SSO) 平台,与 Casbin RBAC 和 ABAC 权限管理集成  具有简单易用、前后端分离、支持多种语言等优点!

Casnode

casnodeicon-default.png?t=N7T8https://casnode.org/

开源论坛和社交平台,StackOverflow和Flarum的替代品

总结

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我变了_我没变

随意 。。。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值