package middleware import ( "net/http" "runtime/debug" "strings" "time" "git.iwork-ai.com/xdc/iqudo-top1/internal/auth" "git.iwork-ai.com/xdc/iqudo-top1/internal/response" "github.com/gin-gonic/gin" "github.com/google/uuid" "go.uber.org/zap" ) func RequestLogger(log *zap.Logger) gin.HandlerFunc { return func(c *gin.Context) { started := time.Now() requestID := c.GetHeader("X-Request-ID") if requestID == "" { requestID = uuid.NewString() } c.Set("request_id", requestID) c.Header("X-Request-ID", requestID) c.Next() duration := time.Since(started) fields := []zap.Field{ zap.String("request_id", requestID), zap.String("method", c.Request.Method), zap.String("path", c.Request.URL.Path), zap.Int("status", c.Writer.Status()), zap.Int("response_bytes", c.Writer.Size()), zap.Int64("duration_ms", duration.Milliseconds()), zap.String("client_ip", c.ClientIP()), } if principal, ok := auth.PrincipalFromContext(c); ok { fields = append(fields, zap.Uint64("tenant_id", principal.TenantID), zap.Uint64("user_id", principal.UserID)) } if len(c.Errors) > 0 { fields = append(fields, zap.String("errors", c.Errors.String())) } switch status := c.Writer.Status(); { case status >= http.StatusInternalServerError: log.Error("http request", fields...) case status >= http.StatusBadRequest: log.Warn("http request", fields...) default: log.Info("http request", fields...) } } } func Recovery(log *zap.Logger) gin.HandlerFunc { return func(c *gin.Context) { defer func() { if recovered := recover(); recovered != nil { log.Error("panic recovered", zap.Any("panic", recovered), zap.ByteString("stack", debug.Stack())) response.Error(c, http.StatusInternalServerError, "INTERNAL_ERROR", "服务暂时不可用") } }() c.Next() } } func Authenticate(service *auth.Service) gin.HandlerFunc { return func(c *gin.Context) { header := c.GetHeader("Authorization") parts := strings.SplitN(header, " ", 2) if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") { response.Error(c, http.StatusUnauthorized, "UNAUTHORIZED", "请先登录") return } principal, err := service.ParseAccessToken(parts[1]) if err != nil { response.Error(c, http.StatusUnauthorized, "INVALID_TOKEN", "登录状态已失效") return } principal, err = service.RefreshPrincipal(principal) if err != nil { response.Error(c, http.StatusUnauthorized, "INVALID_MEMBERSHIP", "账号或企业成员身份已失效") return } auth.SetPrincipal(c, principal) c.Next() } } func RequireAnyPermission(permissions ...string) gin.HandlerFunc { return func(c *gin.Context) { principal, ok := auth.PrincipalFromContext(c) if !ok { response.Error(c, http.StatusUnauthorized, "UNAUTHORIZED", "请先登录") return } if !auth.HasAnyPermission(principal, permissions...) { response.Error(c, http.StatusForbidden, "FORBIDDEN", "没有执行该操作的权限") return } c.Next() } } func RequirePermission(permission string) gin.HandlerFunc { return RequireAnyPermission(permission) }