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 相关文章推荐
go语言-在mac下brew升级golang
Apr 25 Golang
用golang如何替换某个文件中的字符串
Apr 25 Golang
解决golang在import自己的包报错的问题
Apr 29 Golang
golang DNS服务器的简单实现操作
Apr 30 Golang
解决go在函数退出后子协程的退出问题
Apr 30 Golang
Go 在 MongoDB 中常用查询与修改的操作
May 07 Golang
golang中的并发和并行
May 08 Golang
Golang 语言控制并发 Goroutine的方法
Jun 30 Golang
Go语言基础切片的创建及初始化示例详解
Nov 17 Golang
golang生成vcf通讯录格式文件详情
Mar 25 Golang
详解Go语言中配置文件使用与日志配置
Jun 01 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多线程异步请求的3种方法
2014/01/17 PHP
用 Composer构建自己的 PHP 框架之使用 ORM
2014/10/30 PHP
php libevent 功能与使用方法详解
2020/03/04 PHP
php实现的证件照换底色功能示例【人像抠图/换背景图】
2020/05/29 PHP
node.js [superAgent] 请求使用示例
2015/03/13 Javascript
Js获取图片原始宽高的实现代码
2016/05/17 Javascript
JavaScript实现的商品抢购倒计时功能示例
2017/04/17 Javascript
Angular.JS中select下拉框设置value的方法
2017/06/20 Javascript
BootStrap 页签切换失效的解决方法
2017/08/17 Javascript
解决Vue编译时写在style中的路径问题
2017/09/21 Javascript
vue webpack打包优化操作技巧
2018/02/22 Javascript
element ui 对话框el-dialog关闭事件详解
2018/02/26 Javascript
完美解决axios在ie下的兼容性问题
2018/03/05 Javascript
Vue 页面跳转不用router-link的实现代码
2018/04/12 Javascript
JS获取本地地址及天气的方法实例小结
2019/05/10 Javascript
微信小程序地图绘制线段并且测量(实例代码)
2020/01/02 Javascript
js防抖函数和节流函数使用场景和实现区别示例分析
2020/04/11 Javascript
Vue项目配置跨域访问和代理proxy设置方式
2020/09/08 Javascript
Ant design vue中的联动选择取消操作
2020/10/31 Javascript
[04:13]2014DOTA2国际邀请赛 专访DC目前形势不容乐观
2014/07/12 DOTA
Python中的闭包实例详解
2014/08/29 Python
python数据结构之图的实现方法
2015/07/08 Python
使用Python实现BT种子和磁力链接的相互转换
2015/11/09 Python
简单讲解Python中的字符串与字符串的输入输出
2016/03/13 Python
python模块之re正则表达式详解
2017/02/03 Python
详解pandas获取Dataframe元素值的几种方法
2020/06/14 Python
Pandas中DataFrame基本函数整理(小结)
2020/07/20 Python
python uuid生成唯一id或str的最简单案例
2021/01/13 Python
毕业生机械建模求职信
2013/10/14 职场文书
化工专业推荐信范文
2013/11/28 职场文书
行政助理工作职责范本
2014/03/04 职场文书
六查六看剖析材料
2014/10/06 职场文书
离婚被告代理词
2015/05/23 职场文书
创业计划书之寿司
2019/07/19 职场文书
Python中使用Lambda函数的5种用法
2021/04/01 Python
教你使用Pandas直接核算Excel中快递费用
2021/05/12 Python