Skip to content

with gin

在 Go Gin 中使用 Casbin 实现基于角色的访问控制 (RBAC),需要以下步骤:


步骤 1:初始化 Gin 和 Casbin

引入必要模块

确保引入以下依赖:

  • Casbin: 用于权限控制。
  • Gorm-Adapter: Casbin 的数据库适配器。
  • Gin: Web 框架。

安装依赖:

bash
go get -u github.com/gin-gonic/gin
go get -u github.com/casbin/casbin/v2
go get -u github.com/casbin/gorm-adapter/v3

初始化 Casbin 和角色规则

Casbin 模型文件 rbac_model.conf

ini
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

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

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

数据库中的策略可以通过 Gorm-Adapter 进行管理。


步骤 2:编写代码

go
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/casbin/casbin/v2"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"github.com/gin-gonic/gin"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

func main() {
	// 初始化数据库
	db, err := gorm.Open(sqlite.Open("gin_casbin.db"), &gorm.Config{})
	if err != nil {
		log.Fatalf("failed to connect to database: %v", err)
	}

	// 初始化 Casbin 适配器和 Enforcer
	adapter, err := gormadapter.NewAdapterByDB(db)
	if err != nil {
		log.Fatalf("failed to create adapter: %v", err)
	}

	enforcer, err := casbin.NewEnforcer("rbac_model.conf", adapter)
	enforcer.AddGroupingPolicy("alice", "admin")
	enforcer.AddGroupingPolicy("bob", "user")
	// 添加权限规则
	enforcer.AddPolicy("admin", "/data1", "GET")
	enforcer.AddPolicy("user", "/data2", "GET")

	if err != nil {
		log.Fatalf("failed to create enforcer: %v", err)
	}

	// 加载策略
	if err := enforcer.LoadPolicy(); err != nil {
		log.Fatalf("failed to load policy: %v", err)
	}

	// 初始化 Gin 路由
	r := gin.Default()

	// 中间件,用于权限验证
	r.Use(CasbinMiddleware(enforcer))

	// 路由定义
	r.GET("/data1", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"message": "Access granted to data1!"})
	})

	r.GET("/data2", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"message": "Access granted to data2!"})
	})

	// 启动服务
	if err := r.Run(":8080"); err != nil {
		log.Fatalf("failed to start server: %v", err)
	}
}

// Casbin 中间件
func CasbinMiddleware(e *casbin.Enforcer) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 假设从请求头获取用户角色(生产环境应使用更安全的方法)
		user := c.GetHeader("X-User")
		obj := c.Request.URL.Path
		act := c.Request.Method

		// 验证权限
		ok, err := e.Enforce(user, obj, act)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"})
			c.Abort()
			return
		}

		fmt.Println(user, obj, act, ok)
		if !ok {
			c.JSON(http.StatusForbidden, gin.H{"error": "access denied"})
			c.Abort()
			return
		}

		// 权限通过
		c.Next()
	}
}

步骤 3:配置角色和权限

定义角色关系

通过 g 定义用户与角色的关系。例如:

csv
g, alice, admin
g, bob, user

定义权限规则

通过 p 定义角色对资源的访问权限。例如:

csv
p, admin, /data1, GET
p, user, /data2, GET

添加规则到数据库

可通过代码动态添加:

go
// 添加角色关系
enforcer.AddGroupingPolicy("alice", "admin")
enforcer.AddGroupingPolicy("bob", "user")

// 添加权限规则
enforcer.AddPolicy("admin", "/data1", "GET")
enforcer.AddPolicy("user", "/data2", "GET")

// 保存到数据库
enforcer.SavePolicy()

步骤 4:测试

请求示例

假设用户通过 X-User 请求头传递角色信息。

  1. 请求 /data1X-User: alice

    http
    GET /data1
    X-User: alice

    返回:

    json
    {
        "message": "Access granted to data1!"
    }
  2. 请求 /data2X-User: bob

    http
    GET /data2
    X-User: bob

    返回:

    json
    {
        "message": "Access granted to data2!"
    }
  3. 请求未授权的资源:

    http
    GET /data1
    X-User: bob

    返回:

    json
    {
        "error": "access denied"
    }

总结

通过上述代码和配置:

  1. Casbin 的 RBAC 模型可以灵活管理角色与权限。
  2. Gin 中的中间件可以确保每次请求根据策略进行验证。
  3. 策略和角色关系可以存储在数据库中,支持动态调整权限。