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判断key是否在map中的代码
Apr 24 Golang
golang中切片copy复制和等号复制的区别介绍
Apr 27 Golang
golang 生成对应的数据表struct定义操作
Apr 28 Golang
golang 定时任务方面time.Sleep和time.Tick的优劣对比分析
May 05 Golang
修改并编译golang源码的操作步骤
Jul 25 Golang
手把手教你导入Go语言第三方库
Aug 04 Golang
golang 语言中错误处理机制
Aug 30 Golang
Go语言基础切片的创建及初始化示例详解
Nov 17 Golang
Go语言读取txt文档的操作方法
Jan 22 Golang
深入理解 Golang 的字符串
May 04 Golang
Go web入门Go pongo2模板引擎
May 20 Golang
Go语言编译原理之源码调试
Aug 05 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
PHP中函数内引用全局变量的方法
2008/10/20 PHP
PHP提取字符串中的图片地址[正则表达式]
2011/11/12 PHP
解析PHP中$_FILES的使用以及注意事项
2013/07/05 PHP
php中的观察者模式简单实例
2015/01/20 PHP
使用php实现网站验证码功能【推荐】
2017/02/09 PHP
基于JQuery的多标签实现代码
2012/09/19 Javascript
jQuery中对未来的元素绑定事件用bind、live or on
2014/04/17 Javascript
jQuery类选择器用法实例
2014/12/23 Javascript
js实现从中间开始往上下展开网页窗口的方法
2015/03/02 Javascript
JavaScript编程的单例设计模讲解
2015/11/10 Javascript
jQuery实现伪分页的方法分享
2016/02/17 Javascript
基于jQuery实现弹出可关闭遮罩提示框实例代码
2016/07/18 Javascript
VueJS全面解析
2016/11/10 Javascript
jQuery操作复选框(CheckBox)的取值赋值实现代码
2017/01/10 Javascript
微信小程序 中wx.chooseAddress(OBJECT)实例详解
2017/03/31 Javascript
VUE中使用Vue-resource完成交互
2017/07/21 Javascript
Vue-cli-webpack搭建斗鱼直播步骤详解
2017/11/17 Javascript
JavaScript实现简单轮播图效果
2018/12/01 Javascript
js实现下拉框二级联动
2018/12/04 Javascript
解决Vue项目中tff报错的问题
2020/10/21 Javascript
python模块restful使用方法实例
2013/12/10 Python
用map函数来完成Python并行任务的简单示例
2015/04/02 Python
PyQt4 treewidget 选择改变颜色,并设置可编辑的方法
2019/06/17 Python
opencv调整图像亮度对比度的示例代码
2019/09/27 Python
Django xadmin开启搜索功能的实现
2019/11/15 Python
详解CSS3中@media的实际使用
2015/08/04 HTML / CSS
戴森台湾线上商城:Dyson Taiwan
2018/05/21 全球购物
爱普生美国官网:Epson美国
2018/11/05 全球购物
面向对象概念面试题(.NET)
2016/11/04 面试题
什么时候需要进行强制类型转换
2016/09/03 面试题
房屋改造计划书
2014/01/10 职场文书
竞选文艺委员演讲稿
2014/04/28 职场文书
党员活动日总结
2014/05/05 职场文书
2015年社区工作总结
2015/04/08 职场文书
免职通知
2015/04/23 职场文书
校园广播稿范文
2015/08/19 职场文书