fix(hjc): 买家接口未登录统一返回 401,越权返回 403(此前与业务失败同为 code=1)

共享 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 包
This commit is contained in:
2026-09-11 00:03:32 +08:00
parent ce1d0a2a8a
commit 27dbea9b6f
4 changed files with 99 additions and 8 deletions
@@ -0,0 +1,50 @@
package com.gxwebsoft.hjc.auth;
import com.gxwebsoft.common.core.Constants;
import com.gxwebsoft.common.core.web.ApiResult;
/**
* 汇吉采买家接口的统一响应。
*
* <p><b>为什么需要它</b>:共享 {@code SecurityConfig} 里 {@code GET /**} 是放行的,
* 所以未登录的 GET 请求会**进到 controller**,由 controller 自己判登录态。
* 此前这些地方返回的是 {@code fail("用户未登录")},即 {@code code=1}——
* 与「业务失败」同一个码,前端无法据此判定登录失效。</p>
*
* <p>约定(与平台既有常量一致,不新造码值):</p>
* <ul>
* <li>{@code 401} = 未登录 / 凭据失效 → 前端应清凭据并跳登录页</li>
* <li>{@code 403} = 已登录但无权限(由 {@code @PreAuthorize} 抛
* {@code AccessDeniedException} 产生)→ 前端只提示,不清凭据</li>
* </ul>
*
* <p>复用 {@link Constants#UNAUTHENTICATED_CODE} 与 {@link Constants#UNAUTHENTICATED_MSG}
* 这两个常量本就为此准备,此前唯一引用处是被注释掉的代码。</p>
*/
public final class HjcAuthResponses {
private HjcAuthResponses() {
}
/**
* 未登录 / 凭据失效:{@code code=401, message="请先登录"}。
*
* <p>用于 controller 内自行判定登录态的场景(GET 放行时不会经过安全过滤器)。</p>
*/
public static <T> ApiResult<T> unauthorized() {
return new ApiResult<>(Constants.UNAUTHENTICATED_CODE, Constants.UNAUTHENTICATED_MSG);
}
/**
* 已登录但无权访问该资源:{@code code=403}。
*
* <p>与 {@code @PreAuthorize} 抛出的 {@code AccessDeniedException} 归为同一个码,
* 使前端只需记一套规则:401 清凭据跳登录、403 只提示。</p>
*
* @param message 具体原因(例如「无权查看该订单」),直接展示给用户
*/
public static <T> ApiResult<T> forbidden(String message) {
return new ApiResult<>(Constants.UNAUTHORIZED_CODE,
message == null ? Constants.UNAUTHORIZED_MSG : message);
}
}
@@ -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;
@@ -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<String, Object> 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<String, Object> 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()));
@@ -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 只提示。
*
* <p>此前 hjc 买家接口在未登录时返回 {@code code=1}「用户未登录」,与业务失败同码,
* 前端无法据此判定登录失效(PC 端会把它显示成一句错误提示,而不是回登录页)。</p>
*/
class HjcAuthResponsesTest {
@Test
void 未登录必须是401而不是1() {
ApiResult<Object> r = HjcAuthResponses.unauthorized();
assertEquals(401, r.getCode().intValue(), "未登录必须是 401,否则前端无法判定登录失效");
}
@Test
void 未登录文案用平台既有常量() {
assertEquals(Constants.UNAUTHENTICATED_MSG, HjcAuthResponses.unauthorized().getMessage());
}
@Test
void 越权必须是403且保留具体原因() {
ApiResult<Object> r = HjcAuthResponses.forbidden("无权查看该订单");
assertEquals(403, r.getCode().intValue(), "已登录但越权必须是 403(与 @PreAuthorize 同码)");
assertEquals("无权查看该订单", r.getMessage());
}
@Test
void 越权未给原因时用平台默认文案() {
assertEquals(Constants.UNAUTHORIZED_MSG, HjcAuthResponses.forbidden(null).getMessage());
}
}