refactor: 移除全局单例、修复分层违规、统一错误与响应
Some checks failed
Build / build (push) Successful in 7m52s
Build / build-docker (push) Has been cancelled

This commit is contained in:
lafay
2026-06-15 16:40:36 +08:00
parent d9de39a0a3
commit 7d1c78f965
55 changed files with 593 additions and 1744 deletions

View File

@@ -3,6 +3,7 @@ package middleware
import (
"net/http"
"carrotskin/internal/model"
"carrotskin/pkg/auth"
"github.com/gin-gonic/gin"
@@ -15,10 +16,11 @@ func CasbinMiddleware(casbinService *auth.CasbinService, resource, action string
// 从上下文获取用户角色由AuthMiddleware设置
role, exists := c.Get("user_role")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "未授权访问",
})
c.JSON(http.StatusUnauthorized, model.NewErrorResponse(
model.CodeUnauthorized,
model.MsgUnauthorized,
nil,
))
c.Abort()
return
}
@@ -30,10 +32,11 @@ func CasbinMiddleware(casbinService *auth.CasbinService, resource, action string
// 检查权限
if !casbinService.CheckPermission(roleStr, resource, action) {
c.JSON(http.StatusForbidden, gin.H{
"success": false,
"message": "权限不足",
})
c.JSON(http.StatusForbidden, model.NewErrorResponse(
model.CodeForbidden,
model.MsgForbidden,
nil,
))
c.Abort()
return
}
@@ -47,20 +50,22 @@ func RequireAdmin() gin.HandlerFunc {
return func(c *gin.Context) {
role, exists := c.Get("user_role")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "未授权访问",
})
c.JSON(http.StatusUnauthorized, model.NewErrorResponse(
model.CodeUnauthorized,
model.MsgUnauthorized,
nil,
))
c.Abort()
return
}
roleStr, ok := role.(string)
if !ok || roleStr != "admin" {
c.JSON(http.StatusForbidden, gin.H{
"success": false,
"message": "需要管理员权限",
})
c.JSON(http.StatusForbidden, model.NewErrorResponse(
model.CodeForbidden,
"需要管理员权限",
nil,
))
c.Abort()
return
}
@@ -74,20 +79,22 @@ func RequireRole(allowedRoles ...string) gin.HandlerFunc {
return func(c *gin.Context) {
role, exists := c.Get("user_role")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{
"success": false,
"message": "未授权访问",
})
c.JSON(http.StatusUnauthorized, model.NewErrorResponse(
model.CodeUnauthorized,
model.MsgUnauthorized,
nil,
))
c.Abort()
return
}
roleStr, ok := role.(string)
if !ok {
c.JSON(http.StatusForbidden, gin.H{
"success": false,
"message": "权限不足",
})
c.JSON(http.StatusForbidden, model.NewErrorResponse(
model.CodeForbidden,
model.MsgForbidden,
nil,
))
c.Abort()
return
}
@@ -100,10 +107,11 @@ func RequireRole(allowedRoles ...string) gin.HandlerFunc {
}
}
c.JSON(http.StatusForbidden, gin.H{
"success": false,
"message": "权限不足",
})
c.JSON(http.StatusForbidden, model.NewErrorResponse(
model.CodeForbidden,
model.MsgForbidden,
nil,
))
c.Abort()
}
}

View File

@@ -7,18 +7,14 @@ import (
)
// CORS 跨域中间件
func CORS() gin.HandlerFunc {
// 获取配置,如果配置未初始化则使用默认值
var allowedOrigins []string
var isTestEnv bool
if cfg, err := config.GetConfig(); err == nil {
allowedOrigins = cfg.Security.AllowedOrigins
isTestEnv = cfg.IsTestEnvironment()
} else {
// 默认允许所有来源(向后兼容)
func CORS(cfg *config.Config) gin.HandlerFunc {
// 从注入的配置读取 CORS 设置
allowedOrigins := cfg.Security.AllowedOrigins
if len(allowedOrigins) == 0 {
// 默认允许所有来源
allowedOrigins = []string{"*"}
isTestEnv = false
}
isTestEnv := cfg.IsTestEnvironment()
return gin.HandlerFunc(func(c *gin.Context) {
origin := c.GetHeader("Origin")

View File

@@ -5,15 +5,26 @@ import (
"net/http/httptest"
"testing"
"carrotskin/pkg/config"
"github.com/gin-gonic/gin"
)
// testCORSConfig 返回测试用的 CORS 配置(通配符模式)
func testCORSConfig() *config.Config {
return &config.Config{
Security: config.SecurityConfig{
AllowedOrigins: []string{"*"},
},
}
}
// TestCORS_Headers 测试CORS中间件设置的响应头
func TestCORS_Headers(t *testing.T) {
gin.SetMode(gin.TestMode)
router := gin.New()
router.Use(CORS())
router.Use(CORS(testCORSConfig()))
router.GET("/test", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "success"})
})
@@ -55,7 +66,7 @@ func TestCORS_OPTIONS(t *testing.T) {
gin.SetMode(gin.TestMode)
router := gin.New()
router.Use(CORS())
router.Use(CORS(testCORSConfig()))
router.GET("/test", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "success"})
})
@@ -76,7 +87,7 @@ func TestCORS_AllowMethods(t *testing.T) {
gin.SetMode(gin.TestMode)
router := gin.New()
router.Use(CORS())
router.Use(CORS(testCORSConfig()))
router.GET("/test", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "success"})
})
@@ -103,7 +114,7 @@ func TestCORS_AllowHeaders(t *testing.T) {
gin.SetMode(gin.TestMode)
router := gin.New()
router.Use(CORS())
router.Use(CORS(testCORSConfig()))
router.GET("/test", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "success"})
})
@@ -130,7 +141,7 @@ func TestCORS_WithSpecificOrigin(t *testing.T) {
// 注意此测试验证的是在配置了具体allowed origins时的行为
// 在没有配置初始化的情况下,默认使用通配符模式
router := gin.New()
router.Use(CORS())
router.Use(CORS(testCORSConfig()))
router.GET("/test", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "success"})
})