package middlewares import ( "strings" "quyun/v2/app/errorx" "quyun/v2/pkg/consts" "quyun/v2/providers/jwt" "github.com/gofiber/fiber/v3" ) func shouldSkipUserJWTAuth(path, method string) bool { // 仅对明确的公开接口放行,避免误伤其它路径。 if method != fiber.MethodPost { return false } p := strings.TrimSuffix(path, "/") switch p { case "/v1/auth/login", "/v1/auth/register", "/v1/auth/password/reset/sms", "/v1/auth/password/reset/verify", "/v1/auth/password/reset": return true default: return false } } // UserAuth 为平台通用(非租户域)接口提供 JWT 校验,并写入 claims 到 ctx locals。 func (f *Middlewares) UserAuth(c fiber.Ctx) error { if shouldSkipUserJWTAuth(c.Path(), c.Method()) { f.log.Debug("middlewares.user.auth.skipped") return c.Next() } authHeader := c.Get(jwt.HttpHeader) if authHeader == "" { f.log.Info("middlewares.user.auth.missing_token") return errorx.ErrTokenMissing } claims, err := f.jwt.Parse(authHeader) if err != nil { f.log.WithError(err).Warn("middlewares.user.auth.invalid_token") switch err { case jwt.TokenExpired: return errorx.ErrTokenExpired case jwt.TokenMalformed, jwt.TokenNotValidYet, jwt.TokenInvalid: return errorx.ErrTokenInvalid default: return errorx.ErrTokenInvalid } } if claims.UserID == 0 { f.log.Warn("middlewares.user.auth.missing_user_id") return errorx.ErrTokenInvalid } f.log.WithFields(map[string]any{ "user_id": claims.UserID, }).Info("middlewares.user.auth.ok") c.Locals(consts.CtxKeyClaims, claims) return c.Next() }