From 27dbea9b6f87154772c5ee83a35972cba4b20f4b Mon Sep 17 00:00:00 2001 From: "weicw1996@qq.com" Date: Fri, 11 Sep 2026 00:03:32 +0800 Subject: [PATCH] =?UTF-8?q?fix(hjc):=20=E4=B9=B0=E5=AE=B6=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=9C=AA=E7=99=BB=E5=BD=95=E7=BB=9F=E4=B8=80=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=20401=EF=BC=8C=E8=B6=8A=E6=9D=83=E8=BF=94=E5=9B=9E=20?= =?UTF-8?q?403=EF=BC=88=E6=AD=A4=E5=89=8D=E4=B8=8E=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E5=90=8C=E4=B8=BA=20code=3D1=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 共享 SecurityConfig 里 GET /** 放行,未登录的 GET 会进到 controller 由 controller 自行判登录态;此前这些地方返回 fail("用户未登录") 即 code=1,与业务失败同码, 前端无法据此判定登录失效——PC 端会把它显示成一句错误提示,而不是清凭据回登录页。 - 新增 HjcAuthResponses:unauthorized() → 401「请先登录」, forbidden(msg) → 403;复用平台既有常量 Constants.UNAUTHENTICATED_CODE/_MSG (这两个常量本就为此准备,此前唯一引用处是被注释掉的代码),不新造码值 - 7 处未登录返回改为 401:enterprise/my、enterprise/save、 order/create、order/pay、order/mark-paid、order/my、order/{id} - 订单详情的「无权查看该订单」改为 403,与 @PreAuthorize 的 AccessDeniedException 归为同一个码,前端只需记一套规则(401 清凭据跳登录、403 只提示) - 新增 HjcAuthResponsesTest 锁定契约(实测把码值改回 1 则测试红) - 未改动共享 BaseController 与 SecurityConfig,改动面限于 hjc 包 --- .../gxwebsoft/hjc/auth/HjcAuthResponses.java | 50 +++++++++++++++++++ .../controller/HjcEnterpriseController.java | 5 +- .../hjc/controller/HjcOrderController.java | 13 ++--- .../hjc/auth/HjcAuthResponsesTest.java | 39 +++++++++++++++ 4 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/gxwebsoft/hjc/auth/HjcAuthResponses.java create mode 100644 src/test/java/com/gxwebsoft/hjc/auth/HjcAuthResponsesTest.java diff --git a/src/main/java/com/gxwebsoft/hjc/auth/HjcAuthResponses.java b/src/main/java/com/gxwebsoft/hjc/auth/HjcAuthResponses.java new file mode 100644 index 0000000..5400c5b --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/auth/HjcAuthResponses.java @@ -0,0 +1,50 @@ +package com.gxwebsoft.hjc.auth; + +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.web.ApiResult; + +/** + * 汇吉采买家接口的统一响应。 + * + *

为什么需要它:共享 {@code SecurityConfig} 里 {@code GET /**} 是放行的, + * 所以未登录的 GET 请求会**进到 controller**,由 controller 自己判登录态。 + * 此前这些地方返回的是 {@code fail("用户未登录")},即 {@code code=1}—— + * 与「业务失败」同一个码,前端无法据此判定登录失效。

+ * + *

约定(与平台既有常量一致,不新造码值):

+ * + * + *

复用 {@link Constants#UNAUTHENTICATED_CODE} 与 {@link Constants#UNAUTHENTICATED_MSG}: + * 这两个常量本就为此准备,此前唯一引用处是被注释掉的代码。

+ */ +public final class HjcAuthResponses { + + private HjcAuthResponses() { + } + + /** + * 未登录 / 凭据失效:{@code code=401, message="请先登录"}。 + * + *

用于 controller 内自行判定登录态的场景(GET 放行时不会经过安全过滤器)。

+ */ + public static ApiResult unauthorized() { + return new ApiResult<>(Constants.UNAUTHENTICATED_CODE, Constants.UNAUTHENTICATED_MSG); + } + + /** + * 已登录但无权访问该资源:{@code code=403}。 + * + *

与 {@code @PreAuthorize} 抛出的 {@code AccessDeniedException} 归为同一个码, + * 使前端只需记一套规则:401 清凭据跳登录、403 只提示。

+ * + * @param message 具体原因(例如「无权查看该订单」),直接展示给用户 + */ + public static ApiResult forbidden(String message) { + return new ApiResult<>(Constants.UNAUTHORIZED_CODE, + message == null ? Constants.UNAUTHORIZED_MSG : message); + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/controller/HjcEnterpriseController.java b/src/main/java/com/gxwebsoft/hjc/controller/HjcEnterpriseController.java index 6f31114..39d15fc 100644 --- a/src/main/java/com/gxwebsoft/hjc/controller/HjcEnterpriseController.java +++ b/src/main/java/com/gxwebsoft/hjc/controller/HjcEnterpriseController.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.BaseController; import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.auth.HjcAuthResponses; import com.gxwebsoft.hjc.entity.HjcEnterprise; import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial; import com.gxwebsoft.hjc.param.HjcEnterpriseParam; @@ -37,7 +38,7 @@ public class HjcEnterpriseController extends BaseController { public ApiResult my() { Integer userId = getLoginUserId(); if (userId == null) { - return fail("用户未登录"); + return HjcAuthResponses.unauthorized(); } HjcEnterprise enterprise = hjcEnterpriseService.getByUserId(userId); if (enterprise != null) { @@ -53,7 +54,7 @@ public class HjcEnterpriseController extends BaseController { public ApiResult save(@RequestBody HjcEnterprise enterprise) { Integer userId = getLoginUserId(); if (userId == null) { - return fail("用户未登录"); + return HjcAuthResponses.unauthorized(); } HjcEnterprise exist = hjcEnterpriseService.getByUserId(userId); boolean isNew = exist == null; diff --git a/src/main/java/com/gxwebsoft/hjc/controller/HjcOrderController.java b/src/main/java/com/gxwebsoft/hjc/controller/HjcOrderController.java index 9caf49a..9f67cdd 100644 --- a/src/main/java/com/gxwebsoft/hjc/controller/HjcOrderController.java +++ b/src/main/java/com/gxwebsoft/hjc/controller/HjcOrderController.java @@ -8,6 +8,7 @@ import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.hjc.dto.CreateOrderRequest; import com.gxwebsoft.hjc.auth.HjcAdminGuard; import com.gxwebsoft.common.system.entity.User; +import com.gxwebsoft.hjc.auth.HjcAuthResponses; import com.gxwebsoft.hjc.entity.HjcBidProject; import com.gxwebsoft.hjc.entity.HjcEnterprise; import com.gxwebsoft.hjc.entity.HjcOrder; @@ -60,7 +61,7 @@ public class HjcOrderController extends BaseController { public ApiResult create(@RequestBody CreateOrderRequest request) { Integer userId = getLoginUserId(); if (userId == null) { - return fail("用户未登录"); + return HjcAuthResponses.unauthorized(); } HjcEnterprise enterprise = hjcEnterpriseService.getByUserId(userId); if (enterprise == null) { @@ -119,7 +120,7 @@ public class HjcOrderController extends BaseController { public ApiResult pay(@RequestBody Map body) { Integer userId = getLoginUserId(); if (userId == null) { - return fail("用户未登录"); + return HjcAuthResponses.unauthorized(); } String orderNo = body.get("orderNo") == null ? null : String.valueOf(body.get("orderNo")); if (orderNo == null) { @@ -159,7 +160,7 @@ public class HjcOrderController extends BaseController { public ApiResult markPaid(@RequestBody Map body) { Integer userId = getLoginUserId(); if (userId == null) { - return fail("用户未登录"); + return HjcAuthResponses.unauthorized(); } String orderNo = body.get("orderNo") == null ? null : String.valueOf(body.get("orderNo")); if (orderNo == null) { @@ -181,7 +182,7 @@ public class HjcOrderController extends BaseController { public ApiResult my() { Integer userId = getLoginUserId(); if (userId == null) { - return fail("用户未登录"); + return HjcAuthResponses.unauthorized(); } HjcEnterprise enterprise = hjcEnterpriseService.getByUserId(userId); if (enterprise == null) { @@ -200,7 +201,7 @@ public class HjcOrderController extends BaseController { // 枚举出哪些订单 ID 真实存在。 User loginUser = hjcGuard.currentUser(); if (loginUser == null) { - return fail("用户未登录"); + return HjcAuthResponses.unauthorized(); } HjcOrder order = hjcOrderService.getById(id); if (order == null) { @@ -211,7 +212,7 @@ public class HjcOrderController extends BaseController { if (!hjcGuard.isAdmin()) { HjcEnterprise enterprise = hjcEnterpriseService.getByUserId(loginUser.getUserId()); if (enterprise == null || !enterprise.getId().equals(order.getEnterpriseId())) { - return fail("无权查看该订单"); + return HjcAuthResponses.forbidden("无权查看该订单"); } } order.setProject(hjcBidProjectService.getById(order.getProjectId())); diff --git a/src/test/java/com/gxwebsoft/hjc/auth/HjcAuthResponsesTest.java b/src/test/java/com/gxwebsoft/hjc/auth/HjcAuthResponsesTest.java new file mode 100644 index 0000000..64aedf5 --- /dev/null +++ b/src/test/java/com/gxwebsoft/hjc/auth/HjcAuthResponsesTest.java @@ -0,0 +1,39 @@ +package com.gxwebsoft.hjc.auth; + +import com.gxwebsoft.common.core.Constants; +import com.gxwebsoft.common.core.web.ApiResult; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * 响应码契约:前端只认一套规则——401 清凭据跳登录、403 只提示。 + * + *

此前 hjc 买家接口在未登录时返回 {@code code=1}「用户未登录」,与业务失败同码, + * 前端无法据此判定登录失效(PC 端会把它显示成一句错误提示,而不是回登录页)。

+ */ +class HjcAuthResponsesTest { + + @Test + void 未登录必须是401而不是1() { + ApiResult r = HjcAuthResponses.unauthorized(); + assertEquals(401, r.getCode().intValue(), "未登录必须是 401,否则前端无法判定登录失效"); + } + + @Test + void 未登录文案用平台既有常量() { + assertEquals(Constants.UNAUTHENTICATED_MSG, HjcAuthResponses.unauthorized().getMessage()); + } + + @Test + void 越权必须是403且保留具体原因() { + ApiResult r = HjcAuthResponses.forbidden("无权查看该订单"); + assertEquals(403, r.getCode().intValue(), "已登录但越权必须是 403(与 @PreAuthorize 同码)"); + assertEquals("无权查看该订单", r.getMessage()); + } + + @Test + void 越权未给原因时用平台默认文案() { + assertEquals(Constants.UNAUTHORIZED_MSG, HjcAuthResponses.forbidden(null).getMessage()); + } +}