issue_36 #47
@@ -33,10 +33,11 @@ const (
 | 
				
			|||||||
type Response struct {
 | 
					type Response struct {
 | 
				
			||||||
	Code    ResponseCode `json:"code"`           // 业务状态码
 | 
						Code    ResponseCode `json:"code"`           // 业务状态码
 | 
				
			||||||
	Message string       `json:"message"`        // 提示信息
 | 
						Message string       `json:"message"`        // 提示信息
 | 
				
			||||||
	Data    interface{}  `json:"data"`    // 业务数据
 | 
						Data    interface{}  `json:"data,omitempty"` // 业务数据, omitempty表示如果为空则不序列化
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SendResponse 发送统一格式的JSON响应 (基础函数,不带审计)
 | 
					// SendResponse 发送统一格式的JSON响应 (基础函数,不带审计)
 | 
				
			||||||
 | 
					// 所有的业务API都应该使用这个函数返回,以确保HTTP状态码始终为200 OK。
 | 
				
			||||||
func SendResponse(c echo.Context, code ResponseCode, message string, data interface{}) error {
 | 
					func SendResponse(c echo.Context, code ResponseCode, message string, data interface{}) error {
 | 
				
			||||||
	return c.JSON(http.StatusOK, Response{
 | 
						return c.JSON(http.StatusOK, Response{
 | 
				
			||||||
		Code:    code,
 | 
							Code:    code,
 | 
				
			||||||
@@ -46,10 +47,20 @@ func SendResponse(c echo.Context, code ResponseCode, message string, data interf
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SendErrorResponse 发送统一格式的错误响应 (基础函数,不带审计)
 | 
					// SendErrorResponse 发送统一格式的错误响应 (基础函数,不带审计)
 | 
				
			||||||
 | 
					// HTTP状态码为200 OK,通过业务码表示错误。
 | 
				
			||||||
func SendErrorResponse(c echo.Context, code ResponseCode, message string) error {
 | 
					func SendErrorResponse(c echo.Context, code ResponseCode, message string) error {
 | 
				
			||||||
	return SendResponse(c, code, message, nil)
 | 
						return SendResponse(c, code, message, nil)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SendErrorWithStatus 发送带有指定HTTP状态码的错误响应。
 | 
				
			||||||
 | 
					// 这个函数主要用于中间件或特殊场景(如认证失败),在这些场景下需要返回非200的HTTP状态码。
 | 
				
			||||||
 | 
					func SendErrorWithStatus(c echo.Context, httpStatus int, code ResponseCode, message string) error {
 | 
				
			||||||
 | 
						return c.JSON(httpStatus, Response{
 | 
				
			||||||
 | 
							Code:    code,
 | 
				
			||||||
 | 
							Message: message,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// --- 带审计功能的响应函数 ---
 | 
					// --- 带审计功能的响应函数 ---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// setAuditDetails 是一个内部辅助函数,用于在 echo.Context 中设置业务相关的审计信息。
 | 
					// setAuditDetails 是一个内部辅助函数,用于在 echo.Context 中设置业务相关的审计信息。
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,33 +1,34 @@
 | 
				
			|||||||
// Package middleware 存放 gin 中间件
 | 
					// Package middleware 存放中间件
 | 
				
			||||||
package middleware
 | 
					package middleware
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.huangwc.com/pig/pig-farm-controller/internal/app/controller"
 | 
				
			||||||
	"git.huangwc.com/pig/pig-farm-controller/internal/domain/token"
 | 
						"git.huangwc.com/pig/pig-farm-controller/internal/domain/token"
 | 
				
			||||||
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
 | 
						"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
 | 
				
			||||||
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
 | 
						"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
						"github.com/labstack/echo/v4"
 | 
				
			||||||
	"gorm.io/gorm"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AuthMiddleware 创建一个Gin中间件,用于JWT身份验证
 | 
					// AuthMiddleware 创建一个Echo中间件,用于JWT身份验证
 | 
				
			||||||
// 它依赖于 TokenService 来解析和验证 token,并使用 UserRepository 来获取完整的用户信息
 | 
					// 它依赖于 TokenService 来解析和验证 token,并使用 UserRepository 来获取完整的用户信息
 | 
				
			||||||
func AuthMiddleware(tokenService token.Service, userRepo repository.UserRepository) gin.HandlerFunc {
 | 
					func AuthMiddleware(tokenService token.Service, userRepo repository.UserRepository) echo.MiddlewareFunc {
 | 
				
			||||||
	return func(c *gin.Context) {
 | 
						return func(next echo.HandlerFunc) echo.HandlerFunc {
 | 
				
			||||||
 | 
							return func(c echo.Context) error {
 | 
				
			||||||
			// 从 Authorization header 获取 token
 | 
								// 从 Authorization header 获取 token
 | 
				
			||||||
		authHeader := c.GetHeader("Authorization")
 | 
								authHeader := c.Request().Header.Get("Authorization")
 | 
				
			||||||
			if authHeader == "" {
 | 
								if authHeader == "" {
 | 
				
			||||||
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "请求未包含授权标头"})
 | 
									return controller.SendErrorWithStatus(c, http.StatusUnauthorized, controller.CodeUnauthorized, "请求未包含授权标头")
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// 授权标头的格式应为 "Bearer <token>"
 | 
								// 授权标头的格式应为 "Bearer <token>"
 | 
				
			||||||
			parts := strings.Split(authHeader, " ")
 | 
								parts := strings.Split(authHeader, " ")
 | 
				
			||||||
			if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" {
 | 
								if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" {
 | 
				
			||||||
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "授权标头格式不正确"})
 | 
									return controller.SendErrorWithStatus(c, http.StatusUnauthorized, controller.CodeUnauthorized, "授权标头格式不正确")
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			tokenString := parts[1]
 | 
								tokenString := parts[1]
 | 
				
			||||||
@@ -35,27 +36,25 @@ func AuthMiddleware(tokenService token.Service, userRepo repository.UserReposito
 | 
				
			|||||||
			// 解析和验证 token
 | 
								// 解析和验证 token
 | 
				
			||||||
			claims, err := tokenService.ParseToken(tokenString)
 | 
								claims, err := tokenService.ParseToken(tokenString)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "无效的Token"})
 | 
									return controller.SendErrorWithStatus(c, http.StatusUnauthorized, controller.CodeUnauthorized, "无效的Token")
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// 根据 token 中的用户ID,从数据库中获取完整的用户信息
 | 
								// 根据 token 中的用户ID,从数据库中获取完整的用户信息
 | 
				
			||||||
			user, err := userRepo.FindByID(claims.UserID)
 | 
								user, err := userRepo.FindByID(claims.UserID)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
			if err == gorm.ErrRecordNotFound {
 | 
									if errors.Is(err, gorm.ErrRecordNotFound) {
 | 
				
			||||||
					// Token有效,但对应的用户已不存在
 | 
										// Token有效,但对应的用户已不存在
 | 
				
			||||||
				c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "授权用户不存在"})
 | 
										return controller.SendErrorWithStatus(c, http.StatusUnauthorized, controller.CodeUnauthorized, "授权用户不存在")
 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				// 其他数据库查询错误
 | 
									// 其他数据库查询错误
 | 
				
			||||||
			c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "获取用户信息失败"})
 | 
									return controller.SendErrorWithStatus(c, http.StatusInternalServerError, controller.CodeInternalError, "获取用户信息失败")
 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// 将完整的用户对象存储在 context 中,以便后续的处理函数使用
 | 
								// 将完整的用户对象存储在 context 中,以便后续的处理函数使用
 | 
				
			||||||
			c.Set(models.ContextUserKey.String(), user)
 | 
								c.Set(models.ContextUserKey.String(), user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// 继续处理请求链中的下一个处理程序
 | 
								// 继续处理请求链中的下一个处理程序
 | 
				
			||||||
		c.Next()
 | 
								return next(c)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,14 +14,14 @@
 | 
				
			|||||||
        - [x] 适配 `Get...FromContext` 系列函数,使用 `c.Get("key")` 提取数据。
 | 
					        - [x] 适配 `Get...FromContext` 系列函数,使用 `c.Get("key")` 提取数据。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [ ] **3. 中间件 (`internal/app/middleware`)**
 | 
					- [ ] **3. 中间件 (`internal/app/middleware`)**
 | 
				
			||||||
    - [ ] **`auth.go`**
 | 
					    - [x] **`auth.go`**
 | 
				
			||||||
        - [ ] 将 `import "github.com/gin-gonic/gin"` 替换为 `import "github.com/labstack/echo/v4"`。
 | 
					        - [x] 将 `import "github.com/gin-gonic/gin"` 替换为 `import "github.com/labstack/echo/v4"`。
 | 
				
			||||||
        - [ ] 将中间件函数签名从 `func AuthMiddleware(...) gin.HandlerFunc` 更新为
 | 
					        - [x] 将中间件函数签名从 `func AuthMiddleware(...) gin.HandlerFunc` 更新为
 | 
				
			||||||
          `func AuthMiddleware(...) echo.MiddlewareFunc`。
 | 
					          `func AuthMiddleware(...) echo.MiddlewareFunc`。
 | 
				
			||||||
        - [ ] 适配中间件内部逻辑,将 `func(c *gin.Context)` 改造为
 | 
					        - [x] 适配中间件内部逻辑,将 `func(c *gin.Context)` 改造为
 | 
				
			||||||
          `func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { ... } }` 的结构。
 | 
					          `func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { ... } }` 的结构。
 | 
				
			||||||
        - [ ] 将 `c.AbortWithStatusJSON(...)` 调用替换为 `return controller.SendErrorResponse(...)`。
 | 
					        - [x] 将 `c.AbortWithStatusJSON(...)` 调用替换为 `return controller.SendErrorResponse(...)`。
 | 
				
			||||||
        - [ ] 在逻辑正常通过的末尾,调用 `return next(c)`。
 | 
					        - [x] 在逻辑正常通过的末尾,调用 `return next(c)`。
 | 
				
			||||||
    - [ ] **`audit.go`**
 | 
					    - [ ] **`audit.go`**
 | 
				
			||||||
        - [ ] 将 `import "github.com/gin-gonic/gin"` 替换为 `import "github.com/labstack/echo/v4"`。
 | 
					        - [ ] 将 `import "github.com/gin-gonic/gin"` 替换为 `import "github.com/labstack/echo/v4"`。
 | 
				
			||||||
        - [ ] 将中间件函数签名从 `func AuditMiddleware(...) gin.HandlerFunc` 更新为
 | 
					        - [ ] 将中间件函数签名从 `func AuditMiddleware(...) gin.HandlerFunc` 更新为
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user