mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-05-12 02:20:36 +08:00
93 lines
2.7 KiB
Go
93 lines
2.7 KiB
Go
//go:build ignore
|
|
|
|
package httpapi
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"backupx/server/internal/apperror"
|
|
"backupx/server/internal/security"
|
|
"backupx/server/pkg/response"
|
|
"github.com/gin-gonic/gin"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type AuthClaims struct {
|
|
UserID uint
|
|
Username string
|
|
Role string
|
|
}
|
|
|
|
func Recovery(logger *zap.Logger) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
defer func() {
|
|
if recovered := recover(); recovered != nil {
|
|
logger.Error("panic recovered", zap.Any("panic", recovered), zap.String("path", c.Request.URL.Path))
|
|
response.Error(c, http.StatusInternalServerError, "INTERNAL_ERROR", "服务器内部错误")
|
|
c.Abort()
|
|
}
|
|
}()
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func RequestLogger(logger *zap.Logger) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
c.Next()
|
|
logger.Info("http request",
|
|
zap.String("method", c.Request.Method),
|
|
zap.String("path", c.Request.URL.Path),
|
|
zap.Int("status", c.Writer.Status()),
|
|
zap.String("client_ip", c.ClientIP()),
|
|
)
|
|
}
|
|
}
|
|
|
|
func AuthMiddleware(jwtManager *security.JWTManager) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
authorization := strings.TrimSpace(c.GetHeader("Authorization"))
|
|
if authorization == "" || !strings.HasPrefix(strings.ToLower(authorization), "bearer ") {
|
|
response.Error(c, http.StatusUnauthorized, "AUTH_UNAUTHORIZED", "缺少有效的认证令牌")
|
|
c.Abort()
|
|
return
|
|
}
|
|
tokenValue := strings.TrimSpace(strings.TrimPrefix(authorization, "Bearer"))
|
|
if tokenValue == authorization {
|
|
tokenValue = strings.TrimSpace(strings.TrimPrefix(authorization, "bearer"))
|
|
}
|
|
claims, err := jwtManager.Parse(tokenValue)
|
|
if err != nil {
|
|
response.Error(c, http.StatusUnauthorized, "AUTH_UNAUTHORIZED", "认证令牌无效或已过期")
|
|
c.Abort()
|
|
return
|
|
}
|
|
c.Set(claimsContextKey, AuthClaims{UserID: claims.UserID, Username: claims.Username, Role: claims.Role})
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func writeError(c *gin.Context, logger *zap.Logger, err error) {
|
|
var appErr *apperror.AppError
|
|
if errors.As(err, &appErr) {
|
|
if appErr.Err != nil {
|
|
logger.Warn("request failed", zap.String("code", appErr.Code), zap.Error(appErr.Err))
|
|
}
|
|
response.Error(c, appErr.Status, appErr.Code, appErr.Message)
|
|
return
|
|
}
|
|
logger.Error("unexpected error", zap.Error(err))
|
|
response.Error(c, http.StatusInternalServerError, "INTERNAL_ERROR", "服务器内部错误")
|
|
}
|
|
|
|
func bindJSON[T any](c *gin.Context, logger *zap.Logger) (*T, error) {
|
|
var payload T
|
|
if err := c.ShouldBindJSON(&payload); err != nil {
|
|
logger.Warn("bind json failed", zap.Error(err))
|
|
return nil, apperror.Wrap(http.StatusBadRequest, "INVALID_REQUEST", fmt.Sprintf("请求参数错误: %v", err), err)
|
|
}
|
|
return &payload, nil
|
|
}
|