package middleware import ( "encoding/json" "errors" "fmt" "net/http" "hfb_sys/backend/pkg/response" "github.com/gin-gonic/gin" "github.com/redis/go-redis/v9" ) // RequirePermission 检查当前管理员是否拥有指定权限。 // 超级管理员(拥有 super_admin 角色的管理员)自动放行。 func RequirePermission(permCode string, rdb *redis.Client) gin.HandlerFunc { return func(c *gin.Context) { if checkPermission(c, permCode, rdb) { c.Next() } } } func RequirePermissionIf(permCode string, rdb *redis.Client, predicate func(*gin.Context) bool) gin.HandlerFunc { return func(c *gin.Context) { if predicate == nil || !predicate(c) { c.Next() return } if checkPermission(c, permCode, rdb) { c.Next() } } } func checkPermission(c *gin.Context, permCode string, rdb *redis.Client) bool { value, ok := c.Get(ContextAdminID) if !ok { response.Unauthorized(c, "缺少管理员上下文") c.Abort() return false } adminID, ok := value.(uint64) if !ok { response.Unauthorized(c, "管理员上下文无效") c.Abort() return false } codes, err := getPermCodes(c, rdb, adminID) if err != nil { response.Error(c, http.StatusInternalServerError, "perm_check_failed", "权限校验服务暂时不可用") c.Abort() return false } for _, code := range codes { if code == permCode || code == "*" { return true } } response.Error(c, http.StatusForbidden, "forbidden", "没有操作权限") c.Abort() return false } func getPermCodes(c *gin.Context, rdb *redis.Client, adminID uint64) ([]string, error) { if rdb == nil { return nil, errors.New("redis unavailable") } key := fmt.Sprintf("admin:perms:%d", adminID) raw, err := rdb.Get(c.Request.Context(), key).Result() if errors.Is(err, redis.Nil) { return nil, nil // 缓存未命中,视为无权限 } if err != nil { return nil, err } var codes []string if err := json.Unmarshal([]byte(raw), &codes); err != nil { return nil, err } return codes, nil }