/* Package middleware 包含系统的各种中间件 Casbin 权限控制中间件实现了基于 RBAC(Role-Based Access Control)的权限访问控制模型。 该中间件负责: - 验证用户登录状态和账户状态 - 获取用户的角色信息 - 基于角色检查用户对特定资源的访问权限 - 阻止未授权的请求访问受保护的资源 权限控制流程: 1. 从 JWT Token 中获取当前登录用户信息 2. 检查用户账户状态(是否被禁用) 3. 获取用户的所有有效角色 4. 根据请求的 URL 和 HTTP 方法进行权限检查 5. 允许或拒绝请求继续执行 RBAC 模型说明: - Subject(主体):用户的角色关键字 - Object(对象):请求的 API 路径 - Action(动作):HTTP 请求方法(GET、POST、PUT、DELETE 等) */ package middleware import ( "strings" "sync" "github.com/eryajf/go-ldap-admin/config" "github.com/eryajf/go-ldap-admin/public/common" "github.com/eryajf/go-ldap-admin/public/tools" "github.com/eryajf/go-ldap-admin/service/isql" "github.com/gin-gonic/gin" ) // checkLock 权限检查互斥锁 // 确保同一时间只有一个请求在执行权限校验,避免并发访问导致的权限检查异常 var checkLock sync.Mutex // CasbinMiddleware Casbin 权限控制中间件 // 基于 RBAC 模型的权限访问控制中间件,用于保护需要权限验证的 API 接口 // // 权限验证流程: // 1. 获取当前登录用户信息 // 2. 验证用户状态(是否被禁用) // 3. 收集用户的有效角色 // 4. 构建权限检查参数(角色、路径、方法) // 5. 调用 Casbin 引擎进行权限验证 // 6. 根据验证结果决定是否允许请求继续 func CasbinMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // ==================== 用户身份验证 ==================== // 从 JWT Token 中获取当前登录用户信息 user, err := isql.User.GetCurrentLoginUser(c) if err != nil { tools.Response(c, 401, 401, nil, "用户未登录") c.Abort() return } // 检查用户账户状态,禁用用户不允许访问 if user.Status != 1 { tools.Response(c, 401, 401, nil, "当前用户已被禁用") c.Abort() return } // ==================== 角色信息收集 ==================== // 获取用户的所有角色 roles := user.Roles // 收集所有有效角色的关键字(只包含启用状态的角色) var subs []string for _, role := range roles { if role.Status == 1 { subs = append(subs, role.Keyword) } } // ==================== 权限检查参数构建 ==================== // 获取请求的 API 路径(移除 URL 前缀) obj := strings.TrimPrefix(c.FullPath(), "/"+config.Conf.System.UrlPathPrefix) // 获取 HTTP 请求方法 act := c.Request.Method // ==================== 权限验证 ==================== // 调用权限检查函数 isPass := check(subs, obj, act) if !isPass { tools.Response(c, 401, 401, nil, "没有权限") c.Abort() return } // 权限验证通过,继续执行后续中间件和处理函数 c.Next() } } // check 执行具体的权限检查逻辑 // 该函数使用 Casbin 引擎验证用户角色是否有权限访问指定资源 // // 参数说明: // - subs: 用户的角色关键字列表 // - obj: 请求的 API 路径 // - act: HTTP 请求方法 // // 返回值: // - bool: true 表示有权限,false 表示无权限 // // 权限检查策略: // 1. 遍历用户的所有有效角色 // 2. 对每个角色调用 Casbin 引擎进行权限验证 // 3. 只要有一个角色通过验证,就认为用户有权限 // 4. 所有角色都验证失败,则认为用户无权限 func check(subs []string, obj string, act string) bool { // 使用互斥锁确保权限检查的线程安全 // 避免并发请求导致 Casbin 引擎状态异常 checkLock.Lock() defer checkLock.Unlock() isPass := false // 遍历用户的所有角色,进行权限检查 for _, sub := range subs { // 调用 Casbin 引擎进行权限验证 // Enforce(subject, object, action) 检查主体是否有权限对对象执行指定动作 pass, _ := common.CasbinEnforcer.Enforce(sub, obj, act) if pass { isPass = true break // 只要有一个角色通过验证,就认为有权限 } } return isPass }