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 28 Golang
golang 实现对Map进行键值自定义排序
Apr 28 Golang
解决golang post文件时Content-Type出现的问题
May 02 Golang
Golang 实现获取当前函数名称和文件行号等操作
May 08 Golang
Golang实现AES对称加密的过程详解
May 20 Golang
K8s部署发布Golang应用程序的实现方法
Jul 16 Golang
Go语言应该什么情况使用指针
Jul 25 Golang
Golang表示枚举类型的详细讲解
Sep 04 Golang
深入理解go slice结构
Sep 15 Golang
Go 中的空白标识符下划线
Mar 25 Golang
Golang获取List列表元素的四种方式
Apr 20 Golang
GoFrame框架数据校验之校验结果Error接口对象
Jun 21 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中的cookie
2006/11/26 PHP
也谈php网站在线人数统计
2008/04/09 PHP
基于laravel belongsTo使用详解
2019/10/18 PHP
php实现文件上传基本验证
2020/03/04 PHP
基于Jquery的淡入淡出的特效基础练习
2010/12/13 Javascript
基于JQuery 选择器使用说明介绍
2013/04/18 Javascript
Jquery封装tab自动切换效果的具体实现
2013/07/13 Javascript
个人总结的一些JavaScript技巧、实用函数、简洁方法、编程细节
2015/06/10 Javascript
谈一谈JS消息机制和事件机制的理解
2016/04/14 Javascript
js实现div在页面拖动效果
2016/05/04 Javascript
EasyUI学习之Combobox级联下拉列表(2)
2016/12/29 Javascript
Angular.JS实现无限级的联动菜单(使用demo)
2017/02/08 Javascript
Node.js 异步异常的处理与domain模块解析
2017/05/10 Javascript
javascript 取小数点后几位几种方法总结
2017/08/02 Javascript
vue 简单自动补全的输入框的示例
2018/03/12 Javascript
vue-cli脚手架打包静态资源请求出错的原因与解决
2019/06/06 Javascript
Layui表格监听行单双击事件讲解
2019/11/14 Javascript
JavaScript实现tab栏切换效果
2020/03/16 Javascript
javascript+css实现进度条效果
2020/03/25 Javascript
JS 设计模式之:工厂模式定义与实现方法浅析
2020/05/06 Javascript
vue mvvm数据响应实现
2020/11/11 Javascript
[40:29]2018DOTA2亚洲邀请赛 4.7总决赛 LGD vs Mineski 第一场
2018/04/10 DOTA
python编程开发之类型转换convert实例分析
2015/11/13 Python
python django 原生sql 获取数据的例子
2019/08/14 Python
Python3 使用map()批量的转换数据类型,如str转float的实现
2019/11/29 Python
html5 input元素新特性_动力节点Java学院整理
2017/07/06 HTML / CSS
什么是跨站脚本攻击
2014/12/11 面试题
教育学专业毕业生的自我评价
2013/11/21 职场文书
学习之星事迹材料
2014/05/17 职场文书
荒岛余生观后感
2015/06/09 职场文书
七一慰问简报
2015/07/20 职场文书
《坐井观天》教学反思
2016/02/18 职场文书
2019年大学生职业生涯规划书
2019/03/25 职场文书
如何撰写出一份完美的商业计划书?
2019/07/12 职场文书
详解Go语言运用广度优先搜索走迷宫
2021/06/23 Python
Golang 1.18 多模块Multi-Module工作区模式的新特性
2022/04/11 Golang