ldap-1-backend/middleware/CasbinMiddleware.go

143 lines
4.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Package middleware 包含系统的各种中间件
Casbin 权限控制中间件实现了基于 RBACRole-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
}