go语言使用Casbin实现角色的权限控制


Posted in Golang onJune 26, 2021

本文主要介绍了go语言使用Casbin实现角色的权限控制,分享给大家,具体如下:

go语言使用Casbin实现角色的权限控制

介绍 Casbin 是什么?

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

Casbin只负责访问控制。身份认证 authentication(即验证用户的用户名、密码),需要其他专门的身份认证组件负责。例如(jwt-go)

两个核心概念:

访问控制模型model和策略policy。

工作原理:

Casbin把 访问控制模型 被抽象为基于

PERM元模型 (Policy, Effect, Request, Matchers) [策略,效果,请求,匹配器], 反映了权限的本质 ? 访问控制

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

匹配来源:定义的 request 和 存储的 police 比对判断。

所有 model file 中主要就是定义 PERM 4 个部分的一个文件( model.conf , 这个文件一般是固定的)。

因此,切换或升级项目的授权机制与修改配置一样简单。 您可以通过组合可用的模型来定制您自己的访问控制模型(ACL, RBAC, ABAC)。

例如,您可以在一个model中获得RBAC角色和ABAC属性,并共享一组policy规则。

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

rbac_models.conf

# Request definition
[request_definition]
r = sub, obj, act

# Policy definition
[policy_definition]
p = sub, obj, act

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

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

实战

一般运用到项目后台的管理权限中

初始化数据库

初始化环境后,系统会在你选择的数据库自动生成一个casbin_rule的数据库表

go语言使用Casbin实现角色的权限控制

用户权限的增删改查

tips:这些接口,需要放在截器中间件前面, 不然空表无法添加数据

//使用自定义拦截器中间件
r.Use(Authorize())
//增加policy
	r.POST("/api/v1/add", func(c *gin.Context) {
		fmt.Println("增加Policy")
		if ok, _ := Enforcer.AddPolicy("admin", "/api/v1/world", "GET"); !ok {
			fmt.Println("Policy已经存在")
		} else {
			fmt.Println("增加成功")
		}
	})
	//删除policy
	r.DELETE("/api/v1/delete", func(c *gin.Context) {
		fmt.Println("删除Policy")
		if ok, _ := Enforcer.RemovePolicy("admin", "/api/v1/world", "GET"); !ok {
			fmt.Println("Policy不存在")
		} else {
			fmt.Println("删除成功")
		}
	})
	//获取policy
	r.GET("/api/v1/get", func(c *gin.Context) {
		fmt.Println("查看policy")
		list := Enforcer.GetPolicy()
		for _, vlist := range list {
			for _, v := range vlist {
				fmt.Printf("value: %s, ", v)
			}
		}
	})

添加权限,访问其添加接口

go语言使用Casbin实现角色的权限控制

单个用户保存权限的路由是多条记录

go语言使用Casbin实现角色的权限控制

在使用Casbin中间件时,会访问表中的数据库表 ,得到相应的权限信息,增加访问信息后,访问接口成功

go语言使用Casbin实现角色的权限控制

代码

package main

import (
	"fmt"
	"github.com/casbin/casbin"
	xormadapter "github.com/casbin/xorm-adapter"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"net/http"
)

var Enforcer *casbin.Enforcer

func init() {
	CasbinSetup()
}

// 初始化casbin
func CasbinSetup(){
	a, err := xormadapter.NewAdapter("mysql", "root:root123@tcp(127.0.0.1:3306)/casbin?charset=utf8", true)
	if err != nil {
		log.Printf("连接数据库错误: %v", err)
		return
	}
	e, err := casbin.NewEnforcer("./conf/rbac_models.conf", a)
	if err != nil {
		log.Printf("初始化casbin错误: %v", err)
		return
	}

	Enforcer = e
	//return e
}


func Hello(c *gin.Context) {
	fmt.Println("Hello 接收到GET请求..")
	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "Success",
		"data": "Hello 接收到GET请求..",
	})
}


func main() {
	//获取router路由对象
	r := gin.New()


	//增加policy
	r.GET("/api/v1/add", func(c *gin.Context) {
		fmt.Println("增加Policy")
		if ok, _ := Enforcer.AddPolicy("admin", "/api/v1/world", "GET"); !ok {
			fmt.Println("Policy已经存在")
		} else {
			fmt.Println("增加成功")
		}
	})
	//删除policy
	r.DELETE("/api/v1/delete", func(c *gin.Context) {
		fmt.Println("删除Policy")
		if ok, _ := Enforcer.RemovePolicy("admin", "/api/v1/world", "GET"); !ok {
			fmt.Println("Policy不存在")
		} else {
			fmt.Println("删除成功")
		}
	})
	//获取policy
	r.GET("/api/v1/get", func(c *gin.Context) {
		fmt.Println("查看policy")
		list := Enforcer.GetPolicy()
		for _, vlist := range list {
			for _, v := range vlist {
				fmt.Printf("value: %s, ", v)
			}
		}
	})

	//使用自定义拦截器中间件
	r.Use(Authorize())




	//创建请求
	r.GET("/api/v1/hello", Hello)
	r.Run(":9000") //参数为空 默认监听8080端口
}




//拦截器
func Authorize() gin.HandlerFunc {

	return func(c *gin.Context) {
		//var e *casbin.Enforcer
		e := Enforcer

		//从DB加载策略
		e.LoadPolicy()

		//获取请求的URI
		obj := c.Request.URL.RequestURI()
		//获取请求方法
		act := c.Request.Method
		//获取用户的角色 应该从db中读取
		sub := "admin"

		//判断策略中是否存在
		if ok, _ := e.Enforce(sub, obj, act); ok {
			fmt.Println("恭喜您,权限验证通过")
			c.Next() // 进行下一步操作
		} else {
			fmt.Println("很遗憾,权限验证没有通过")
			c.Abort()
		}
	}
}

总代码

package main

import (
	"fmt"
	"github.com/casbin/casbin"
	xormadapter "github.com/casbin/xorm-adapter"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"net/http"
)

var Enforcer *casbin.Enforcer

func init() {
	CasbinSetup()
}

// 初始化casbin
func CasbinSetup(){
	a, err := xormadapter.NewAdapter("mysql", "root:root123@tcp(127.0.0.1:3306)/casbin?charset=utf8", true)
	if err != nil {
		log.Printf("连接数据库错误: %v", err)
		return
	}
	e, err := casbin.NewEnforcer("./conf/rbac_models.conf", a)
	if err != nil {
		log.Printf("初始化casbin错误: %v", err)
		return
	}

	Enforcer = e
	//return e
}


func Hello(c *gin.Context) {
	fmt.Println("Hello 接收到GET请求..")
	c.JSON(http.StatusOK, gin.H{
		"code": 200,
		"msg":  "Success",
		"data": "Hello 接收到GET请求..",
	})
}


func main() {
	//获取router路由对象
	r := gin.New()


	//增加policy
	r.GET("/api/v1/add", func(c *gin.Context) {
		fmt.Println("增加Policy")
		if ok, _ := Enforcer.AddPolicy("admin", "/api/v1/world", "GET"); !ok {
			fmt.Println("Policy已经存在")
		} else {
			fmt.Println("增加成功")
		}
	})
	//删除policy
	r.DELETE("/api/v1/delete", func(c *gin.Context) {
		fmt.Println("删除Policy")
		if ok, _ := Enforcer.RemovePolicy("admin", "/api/v1/world", "GET"); !ok {
			fmt.Println("Policy不存在")
		} else {
			fmt.Println("删除成功")
		}
	})
	//获取policy
	r.GET("/api/v1/get", func(c *gin.Context) {
		fmt.Println("查看policy")
		list := Enforcer.GetPolicy()
		for _, vlist := range list {
			for _, v := range vlist {
				fmt.Printf("value: %s, ", v)
			}
		}
	})

	//使用自定义拦截器中间件
	r.Use(Authorize())




	//创建请求
	r.GET("/api/v1/hello", Hello)
	r.Run(":9000") //参数为空 默认监听8080端口
}




//拦截器
func Authorize() gin.HandlerFunc {

	return func(c *gin.Context) {
		//var e *casbin.Enforcer
		e := Enforcer

		//从DB加载策略
		e.LoadPolicy()

		//获取请求的URI
		obj := c.Request.URL.RequestURI()
		//获取请求方法
		act := c.Request.Method
		//获取用户的角色 应该从db中读取
		sub := "admin"

		//判断策略中是否存在
		if ok, _ := e.Enforce(sub, obj, act); ok {
			fmt.Println("恭喜您,权限验证通过")
			c.Next() // 进行下一步操作
		} else {
			fmt.Println("很遗憾,权限验证没有通过")
			c.Abort()
		}
	}
}

封装后的代码

package mycasbin

import (
	"simple-api/mongoose"
	"github.com/casbin/mongodb-adapter"
	"github.com/casbin/casbin"
	"gopkg.in/mgo.v2/bson"
)

type CasbinModel struct {
	ID       bson.ObjectId `json:"id" bson:"_id"`
	Ptype    string        `json:"ptype" bson:"ptype"`
	RoleName string        `json:"rolename" bson:"v0"`
	Path     string        `json:"path" bson:"v1"`
	Method   string        `json:"method" bson:"v2"`
}

//添加权限
func (c *CasbinModel) AddCasbin(cm CasbinModel) bool {
	e := Casbin()
	e.AddPolicy(cm.RoleName, cm.Path, cm.Method)
	return true

}

//持久化到数据库
// "github.com/casbin/mongodb-adapter"
// func Casbin() *casbin.Enforcer {
// 	a := mongodbadapter.NewAdapter(mongoose.MongoUrl)
// 	e := casbin.NewEnforcer("conf/auth_model.conf", a)
// 	e.LoadPolicy()
// 	return e
// }
func Casbin() *casbin.Enforcer {
	a := mongodbadapter.NewAdapter(mongoose.MongoUrl)
	e, err := casbin.NewEnforcer("conf/auth_model.conf", a)
	if err != nil {
		panic(err)
	}
	e.LoadPolicy()
	return e
}
package apis

import (
	"net/http"
	"simple-api/utils/mycasbin"

	"github.com/gin-gonic/gin"
	"gopkg.in/mgo.v2/bson"
)

var (
	casbins = mycasbin.CasbinModel{}
)

func AddCasbin(c *gin.Context) {
	rolename := c.PostForm("rolename")
	path := c.PostForm("path")
	method := c.PostForm("method")
	ptype := "p"
	casbin := mycasbin.CasbinModel{
		ID:       bson.NewObjectId(),
		Ptype:    ptype,
		RoleName: rolename,
		Path:     path,
		Method:   method,
	}
	isok := casbins.AddCasbin(casbin)
	if isok {
		c.JSON(http.StatusOK, gin.H{
			"success": true,
			"msg":     "保存成功",
		})
	} else {
		c.JSON(http.StatusOK, gin.H{
			"success": false,
			"msg":     "保存失败",
		})
	}
}

参考

https://www.jianshu.com/p/9506406e745f

到此这篇关于go语言使用Casbin实现角色的权限控制的文章就介绍到这了,更多相关go语言角色权限控制内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Golang 相关文章推荐
用golang如何替换某个文件中的字符串
Apr 25 Golang
golang在GRPC中设置client的超时时间
Apr 27 Golang
Go 实现英尺和米的简单单位换算方式
Apr 29 Golang
Go遍历struct,map,slice的实现
Jun 13 Golang
Go语言设计模式之结构型模式
Jun 22 Golang
Go 语言下基于Redis分布式锁的实现方式
Jun 28 Golang
golang实现一个简单的websocket聊天室功能
Oct 05 Golang
浅谈GO中的Channel以及死锁的造成
Mar 18 Golang
Golang 遍历二叉树
Apr 19 Golang
GoFrame gredis缓存DoVar Conn连接对象 自动序列化GoFrame gredisDo/DoVar方法Conn连接对象自动序列化/反序列化总结
Jun 14 Golang
Golang gRPC HTTP协议转换示例
Jun 16 Golang
Go gorilla securecookie库的安装使用详解
Aug 14 Golang
Go语言设计模式之结构型模式
浅谈Go语言多态的实现与interface使用
Jun 16 #Golang
再次探讨go实现无限 buffer 的 channel方法
Jun 13 #Golang
Go遍历struct,map,slice的实现
Jun 13 #Golang
go web 预防跨站脚本的实现方式
Jun 11 #Golang
Golang生成Excel文档的方法步骤
Go timer如何调度
You might like
分页显示Oracle数据库记录的类之二
2006/10/09 PHP
php中http_build_query 的一个问题
2012/03/25 PHP
深入解读php中关于抽象(abstract)类和抽象方法的问题分析
2014/01/03 PHP
Yii2 rbac权限控制之菜单menu实例教程
2016/04/28 PHP
[原创]smarty简单模板变量输出方法
2016/07/09 PHP
php fseek函数读取大文件两种方法
2016/10/12 PHP
PHP从零开始打造自己的MVC框架之路由类实现方法分析
2019/06/03 PHP
Laravel框架下的Contracts契约详解
2020/03/17 PHP
javascript十个最常用的自定义函数(中文版)
2009/09/07 Javascript
在js(jquery)中获得文本框焦点和失去焦点的方法
2012/12/04 Javascript
jQuery实现的数值范围range2dslider选取插件特效多款代码分享
2015/08/27 Javascript
JS实现黑色大气的二级导航菜单效果
2015/09/18 Javascript
JavaScript利用HTML DOM进行文档操作的方法
2016/03/28 Javascript
使用JavaScript获取Request中参数的值方法
2016/09/27 Javascript
Vue用v-for给循环标签自身属性添加属性值的方法
2018/10/18 Javascript
微信小程序事件 bindtap bindinput代码实例
2019/08/26 Javascript
Javascript实现简易天数计算器
2020/05/18 Javascript
python使用cookielib库示例分享
2014/03/03 Python
Python引用模块和查找模块路径
2016/03/17 Python
python使用webdriver爬取微信公众号
2018/08/31 Python
Python PyAutoGUI模块控制鼠标和键盘实现自动化任务详解
2018/09/04 Python
在python中实现调用可执行文件.exe的3种方法
2019/07/07 Python
用python实现学生管理系统
2020/07/24 Python
Python之多进程与多线程的使用
2021/02/23 Python
CSS3 RGBA色彩模式使用实例讲解
2016/04/26 HTML / CSS
html5教程制作简单画板代码分享
2013/12/04 HTML / CSS
探索HTML5本地存储功能运用技巧
2016/03/02 HTML / CSS
详解html2canvas截图不能截取圆角图片的解决方案
2018/01/30 HTML / CSS
Bluebella法国官网:英国性感内衣品牌
2019/05/03 全球购物
雷朋巴西官方商店:Ray-Ban Brasil
2020/07/21 全球购物
最新奶茶店创业计划书范文
2014/02/08 职场文书
节能环保演讲稿
2014/08/28 职场文书
邮政竞聘演讲稿
2014/09/03 职场文书
机关职员工作检讨书
2014/10/23 职场文书
创业计划书之废品回收
2019/09/26 职场文书
python爬虫请求库httpx和parsel解析库的使用测评
2021/05/10 Python