Casbin初次使用 | 豆包MarsCode AI刷题

206 阅读4分钟

一、Casbin 简介

Casbin 是一个强大的、高效的开源访问控制框架,支持多种访问控制模型(ACL、RBAC、ABAC 等),主要用于对用户的权限进行动态管理。Casbin 提供了一种灵活的权限管理方式,开发者可以根据实际需求,自定义访问控制策略。

主要特点:

• 支持多种访问控制模型(ACL、RBAC、ABAC)。

• 通过策略文件灵活管理权限规则。

• 支持多种存储后端(如内存、文件、数据库等)。

• 支持权限管理的实时更新。

二、Casbin 的基本概念

在 Casbin 中,权限控制由三部分组成:

  1. 模型(Model): 定义了权限控制的逻辑规则。

  2. 策略(Policy): 定义了权限数据,如谁可以访问什么资源、做什么操作。

  3. 请求(Request): 用户的访问请求,用于验证权限。

Casbin 的模型文件通常是一个 .conf 文件,定义了访问控制逻辑,主要包含以下部分:

请求定义([request_definition]): 定义访问请求的结构(如用户、资源、操作)。

策略定义([policy_definition]): 定义权限策略的结构。

角色定义([role_definition]): 定义角色继承关系,用于 RBAC。

策略效果([policy_effect]): 定义多条策略规则的效果(如允许/拒绝)。

匹配器([matchers]): 定义请求和策略的匹配规则。

三.实践

package casbin

import (
	"context"

	"github.com/casbin/casbin/v2"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/kitex/pkg/klog"
	"github.com/czczcz831/tiktok-mall/app/api/conf"
	"github.com/czczcz831/tiktok-mall/app/user/biz/dal/mysql"
	"github.com/czczcz831/tiktok-mall/common/utils"

	gormadapter "github.com/casbin/gorm-adapter/v3"
	casbinHertz "github.com/hertz-contrib/casbin"
)

var (
	CasbinEnforcer        *casbin.Enforcer
	CasbinHertzMiddleware *casbinHertz.Middleware
)

const (
	ADMIN_ROLE    = "Admin"
	CUSTOMER_ROLE = "Customer"
	SELLER_ROLE   = "Seller"
)

const (
	CUSTOMER_OBJECT = "customer_obj"
	SELLER_OBJECT   = "seller_obj"
)

func SubjectFromToken(ctx context.Context, c *app.RequestContext) string {
	token := c.GetRequest().Header.Get("Authorization")
	if token == "" {
		return ""
	}

	publicKeyHexString := conf.GetConf().JWT.PublicSecret

	uuid, _, err := utils.VerifyToken(token, publicKeyHexString)

	if err != nil {
		return ""
	}

	return uuid
}

func Init() {
	a, err := gormadapter.NewAdapterByDB(mysql.DB)

	if err != nil {
		klog.Fatalf("new casbin enforcer failed: %v", err)
	}

	CasbinEnforcer, err = casbin.NewEnforcer("casbin.conf", a)
	if err != nil {
		klog.Fatalf("new casbin enforcer failed: %v", err)
	}
	CasbinEnforcer.EnableAutoSave(true)

	err = CasbinEnforcer.LoadPolicy()
	if err != nil {
		klog.Fatalf("load policy failed: %v", err)
	}

	//初始化
	//AdminRole
	CasbinEnforcer.AddPolicy(ADMIN_ROLE, "*", "*")
	//CustomerRole
	CasbinEnforcer.AddPolicy(CUSTOMER_ROLE, CUSTOMER_OBJECT, "*")
	//SellerRole
	CasbinEnforcer.AddPolicy(SELLER_ROLE, SELLER_OBJECT, "*")
	CasbinEnforcer.AddPolicy(SELLER_ROLE, CUSTOMER_OBJECT, "*")

	//Superuser
	CasbinEnforcer.AddRoleForUser("superuser-uuid", ADMIN_ROLE)

	CasbinEnforcer.SavePolicy()

	if err != nil {
		klog.Fatalf("load policy failed: %v", err)
	}

	CasbinHertzMiddleware, err = casbinHertz.NewCasbinMiddlewareFromEnforcer(CasbinEnforcer, SubjectFromToken)
	if err != nil {
		klog.Fatalf("new casbin middleware failed: %v", err)
	}

}

在我们的电商系统中,不同角色的用户需要拥有不同的权限,比如管理员可以访问所有资源,客户只能查看自己的信息,卖家则可以管理店铺以及和客户进行互动。为了实现这些需求,我使用了 Casbin,一个灵活的权限管理框架,它支持基于角色的访问控制(RBAC),并且可以通过数据库存储策略,方便动态管理。

代码的核心逻辑主要分为几个部分。首先是初始化 Casbin 的逻辑。在 Init 函数中,我通过 gormadapter.NewAdapterByDB 将 MySQL 数据库作为策略存储后端,并加载了一个 Casbin 的模型配置文件(casbin.conf)。这一步非常重要,因为 Casbin 需要知道如何匹配请求和策略,以及如何定义角色和权限关系。模型文件中包含了基础的权限匹配规则,比如用户、资源和操作的结构。

初始化后,我定义了几种角色及其对应的权限。我们有三个主要角色:管理员(Admin)、客户(Customer)和卖家(Seller)。通过 AddPolicy 方法,我分别为这三个角色赋予了不同的权限。例如,管理员可以访问所有资源(* 表示通配符),客户只能访问客户相关的资源,卖家既可以访问卖家资源,也可以与客户资源进行交互。

此外,我还为一个超级用户指定了管理员角色。这里使用了 AddRoleForUser 方法,通过用户的 UUID 来绑定角色,这样超级用户就可以拥有管理员的权限。我们还开启了 EnableAutoSave 功能,这样每次对策略的更改都会自动保存到数据库,避免忘记保存带来的问题。

在权限验证的过程中,我们需要从用户的请求中提取身份信息。为此,我实现了 SubjectFromToken 方法,它从请求头中获取 Authorization Token,并通过 JWT 解密来提取用户的 UUID。这个 UUID 就是权限校验时的主体(sub)。

为了让 Casbin 和我们的 Web 框架 Hertz 集成,我通过 casbinHertz.NewCasbinMiddlewareFromEnforcer 方法初始化了一个 Casbin 中间件,并将上面提取用户身份的逻辑绑定到中间件中。这个中间件会在每次请求时拦截并验证权限,确保用户只能访问他们被授权的资源。

整体上,这套权限管理方案清晰而灵活。Casbin 的核心在于模型和策略的分离,通过动态地加载和更新策略,我们可以轻松地适应业务需求的变化,比如为新角色赋予权限或者调整现有角色的权限。而通过数据库持久化存储策略,也避免了重启服务时权限数据丢失的问题。

总结来说,Casbin 为我们的电商系统提供了一个强大的权限管理工具,它不仅实现了 RBAC 的基础功能,还通过与 JWT 和 Hertz 的集成,使整个权限校验过程高效、透明。对开发者来说,只需要关注模型配置和策略定义,复杂的权限验证工作都交给了 Casbin 和中间件来处理,非常省心。