前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何在项目中加入casbin进行简单的权限验证

如何在项目中加入casbin进行简单的权限验证

原创
作者头像
陈杪秋
发布2024-03-10 14:02:05
1360
发布2024-03-10 14:02:05

前言

casbin是目前流行的身份鉴定工具之一,笔者在近期写的一个项目中也使用到了casbin对于项目的权限进行鉴定,于是在此分享一下笔者是如何使用casbin进行权限判定的。

注意:以下权限验证方式以golang gin gorm为例

安装

安装casbin直接以官网示例进行即可,在此给出官网网址:https://casbin.org/docs/get-started

如果需要将策略存储至数据库,则可以使用对应的Adapter,在此给出Adapter官网网址:https://casbin.org/docs/adapters

如笔者使用的是go+Gorm,选择对应的Adapter即可

模型选择

因为要进行权限验证以及动态修改用户权限,在此选择casbin的RBAC模型,具体配置文件如下

代码语言:conf
复制
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act, eft

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))

[matchers]
m = g(r.sub, p.sub) && keyMatch(r.act, p.act) && keyMatch(r.obj, p.obj)

其中keyMatch()为官方提供的函数,具体匹配方法如下

代码语言:go
复制
func KeyMatch(key1 string, key2 string) bool {
    i := strings.Index(key2, "*")
    if i == -1 {
        return key1 == key2
    }

    if len(key1) > i {
        return key1[:i] == key2[:i]
    }
    return key1 == key2[:i]
}

初始化配置

初始化casbin可以参考官方示例:https://casbin.org/zh/docs/get-started

在此给出个人初始化方法

casbin.go

代码语言:go
复制
package auth

import (
	"os"

	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
)

var Casbin *casbin.Enforcer

func InitCasbin() {
    // os.Getenv("MYSQL_DSN")可以参考gorm官方示例:
    //user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
	a, err := gormadapter.NewAdapter("mysql", os.Getenv("MYSQL_DSN"), true)
	if err != nil {
		panic(err)
	}

	m, err := model.NewModelFromString(`
	[request_definition]
	r = sub, obj, act
	
	[policy_definition]
	p = sub, obj, act, eft
	
	[role_definition]
	g = _, _
	
	[policy_effect]
	e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
	
	[matchers]
	m = g(r.sub, p.sub) && keyMatch(r.act, p.act) && keyMatch(r.obj, p.obj)
	`)
	if err != nil {
		panic(err)
	}

	e, err := casbin.NewEnforcer(m, a)
	if err != nil {
		panic(err)
	}
	Casbin = e

	Casbin.LoadPolicy()

    // 检查基础权限是否存在,请按需修改
	if ok, _ := Casbin.Enforce("common_admin", "admin/user", "POST"); !ok {
		initPolicy()
	}
}

初始化基础策略,在此给出个人写法,可以自行调整

initPolicy

代码语言:go
复制
func initPolicy() {
	// add base policies
    // 注意,此处一定要填写allow或deny,否则会报错
	Casbin.AddPolicies(
		[][]string{
            //  写入对应权限,请自行调整
			// suspend user can't do anything
			{model.StatusSuspendUser, "*", "*", "deny"},
			// inactive user can't create
			{model.StatusInactiveUser, "user*", "*", "allow"},
			{model.StatusInactiveUser, "file*", "GET", "allow"},
			{model.StatusInactiveUser, "file*", "DELETE", "allow"},
			{model.StatusInactiveUser, "filefolder*", "GET", "allow"},
			{model.StatusInactiveUser, "filefolder*", "DELETE", "allow"},
			{model.StatusInactiveUser, "filestore*", "GET", "allow"},
			{model.StatusInactiveUser, "share*", "GET", "allow"},
			{model.StatusInactiveUser, "share*", "DELETE", "allow"},
			// active user can create file, filefolder and share
			{model.StatusActiveUser, "share*", "*", "allow"},
			{model.StatusActiveUser, "file*", "*", "allow"},
			{model.StatusActiveUser, "filefolder*", "*", "allow"},
			{model.StatusActiveUser, "rank*", "GET", "allow"},
			// admin user can change user status
			{model.StatusAdmin, "admin/user*", "*", "allow"},
			{model.StatusAdmin, "admin/login*", "*", "allow"},
			// super admin can do anything
			{model.StatusSuperAdmin, "*", "*", "allow"},
		},
	)
	// add group policies
	Casbin.AddGroupingPolicies(
		[][]string{
			{model.StatusActiveUser, model.StatusInactiveUser},
			{model.StatusAdmin, model.StatusActiveUser},
		},
	)
	Casbin.SavePolicy()
}

具体名称含义

代码语言:go
复制
const (
	// super admin
	StatusSuperAdmin = "super_admin"
	// admin User
	StatusAdmin = "common_admin"
	// active User
	StatusActiveUser = "active"
	// inactive User
	StatusInactiveUser = "inactive"
	// Suspend User
	StatusSuspendUser = "suspend"
)

后续直接在启动服务的时候进行初始化即可

代码语言:go
复制
func Init() {
    //其他初始化
    ............
	// start casbin
	auth.InitCasbin()
}

中间件写法

casbin已经配置好了,接下来就是编写中间件进行权限验证,在此给出gin中间件写法

代码语言:go
复制
func CasbinAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
        // 获取用户状态,此处已将状态写入gin.context
		userStatus := c.MustGet("Status").(string)
        // 获取用户申请的资源和方法
		method := c.Request.Method
		path := c.Request.URL.Path
        //过滤默认头部,这里将/api/v1/ 过滤
		object := strings.TrimPrefix(path, "/api/v1/")

        // 使用casbin提供的函数进行权限验证
		if ok, _ := auth.Casbin.Enforce(userStatus, object, method); !ok {
			// 如果无权限则返回无权限
            c.JSON(200, serializer.NotAuthErr("not auth"))
            // 中断后续执行
			c.Abort()
		}
	}
}

最后将中间件加入路由即可,在此给出个人使用gin框架写法

代码语言:go
复制
v1 := r.Group("/api/v1")
	{
		auth := v1.Group("")
		auth.Use(middleware.CasbinAuth())
		{
            // 放入需要权限验证的api
		}
	}

一个需要注意的问题

Q:如果需要动态修改权限怎么办?

A:如果想要修改用户权限,直接修改存储的用户身份即可。

如果想要添加新的权限或删除权限请使用casbin的对应函数,在此给出go的官方api

代码语言:go
复制
// e.AddPolicy(...)
// e.RemovePolicy(...)
// Save the policy back to DB.
e.SavePolicy()

不要在initPolicy进行修改,因为这样并不会将权限加入数据库。如果想要在initPolicy进行修改,请删除数据库中casbin自动创建的casbin_rule表。

结尾

如果有更多疑问,可以在评论区留言

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 安装
  • 模型选择
  • 初始化配置
  • 中间件写法
  • 一个需要注意的问题
  • 结尾
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档