From 53e5d81fa89dc01eeb9a3c3f217e607ea1ffe4cd Mon Sep 17 00:00:00 2001 From: Zuncle <34310384@qq.com> Date: Thu, 26 Mar 2026 14:35:25 +0800 Subject: [PATCH] =?UTF-8?q?fix(auth):=20=E5=95=86=E5=93=81=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E6=8E=A5=E5=8F=A3=E7=A7=BB=E8=87=B3=E5=85=AC=E5=BC=80?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=9C=AA=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E6=B5=8F=E8=A7=88=E8=A7=A6=E5=8F=91=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题背景: - 平台审核失败,原因:小程序页面未完整浏览即要求授权登录,属于登录规范不合规 - GET /api/app/products/:id 位于认证路由组,未登录用户访问返回 401, 触发前端全局拦截器弹出"账号登录已过期"弹窗 修改内容: 1. router.go: 将 GET /products/:id 从 appAuthApiRouter(认证组) 移至 appPublicApiRouter(公开组),允许未登录用户浏览商品详情 2. product.go: 针对公开端点增加安全加固 - 增加商品 ID 参数校验(ParseInt 错误和 id<=0) - 将兜底错误信息从 validation.Error(err) 改为通用提示 "商品信息获取失败",防止原始 DB 错误泄露给未认证请求 影响范围: - 仅影响 GET /api/app/products/:id 端点 - GET /api/app/products(商品列表)仍保留在认证组 - 该 handler 不依赖 JWT session 上下文,移至公开组后功能无变化 - 返回数据仅包含商品元信息(名称、图片、价格、库存),不含用户敏感数据 --- internal/api/app/product.go | 8 ++++++-- internal/router/router.go | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/api/app/product.go b/internal/api/app/product.go index e579ab0..574c1f1 100755 --- a/internal/api/app/product.go +++ b/internal/api/app/product.go @@ -121,7 +121,11 @@ type getAppProductDetailResponse struct { func (h *productHandler) GetProductDetailForApp() core.HandlerFunc { return func(ctx core.Context) { idStr := ctx.Param("id") - id, _ := strconv.ParseInt(idStr, 10, 64) + id, err := strconv.ParseInt(idStr, 10, 64) + if err != nil || id <= 0 { + ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "无效的商品ID")) + return + } d, err := h.product.GetDetailForApp(ctx.RequestContext(), id) if err != nil { if err.Error() == "PRODUCT_OFFSHELF" { @@ -132,7 +136,7 @@ func (h *productHandler) GetProductDetailForApp() core.HandlerFunc { ctx.AbortWithError(core.Error(http.StatusOK, 20002, "商品缺货")) return } - ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ServerError, validation.Error(err))) + ctx.AbortWithError(core.Error(http.StatusInternalServerError, code.ServerError, "商品信息获取失败")) return } ptsDetail := h.user.CentsToPointsFloat(ctx.RequestContext(), d.Price) diff --git a/internal/router/router.go b/internal/router/router.go index ff7e65d..eaf8c41 100755 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -462,6 +462,7 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo) (core.Mux, func(), er // 商城浏览(无需登录) appPublicApiRouter.GET("/store/items", appapi.NewStore(logger, db, userSvc).ListStoreItemsForApp()) appPublicApiRouter.GET("/product_categories", appapi.NewProductCategory(logger, db).ListProductCategoriesForApp()) + appPublicApiRouter.GET("/products/:id", appapi.NewProduct(logger, db, userSvc).GetProductDetailForApp()) } // 公开接口路由组 (无需登录) @@ -514,7 +515,6 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo) (core.Mux, func(), er appAuthApiRouter.GET("/orders/:order_id", userHandler.GetOrderDetail()) appAuthApiRouter.POST("/orders/:order_id/cancel", userHandler.CancelOrder()) appAuthApiRouter.GET("/products", appapi.NewProduct(logger, db, userSvc).ListProductsForApp()) - appAuthApiRouter.GET("/products/:id", appapi.NewProduct(logger, db, userSvc).GetProductDetailForApp()) appAuthApiRouter.GET("/lottery/result", activityHandler.LotteryResultByOrder()) // 需要黑名单检查的抽奖接口组