当前位置 博文首页 > go语言使用Casbin实现角色的权限控制

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

    作者:王大阳_ 时间:2021-08-02 17:58

    目录
    • 介绍 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的数据库表

          在这里插入图片描述

          用户权限的增删改查

          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)
          			}
          		}
          	})
          

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

          在这里插入图片描述

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

          在这里插入图片描述

          在使用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

          jsjbwy
          下一篇:没有了