Răsfoiți Sursa

fix(security): 公开接口识别登录用户,修复供应商体系可见性对小程序失效

根因:/api/product/list、/api/product/detail 被 WebConfig 从 JwtInterceptor
注册中排除(excludePathPatterns),且 JwtInterceptor 对 PUBLIC_PATHS 白名单
路径直接短路 return,导致商品列表/详情接口永远拿不到 userId,所有用户被
当作游客处理。ProductService.list() 的 vendor_visible(同体系内可见)过滤
因此从未生效:登录的体系成员也看不到本体系的 vendor 商品。

修复:
- JwtInterceptor: 白名单路径不再短路,改为“携有效 token 则解析用户上下文,
  无/无效 token 则匿名放行”(保持游客可浏览,仅新增登录用户识别)。
- WebConfig: 从 jwtInterceptor 的 excludePathPatterns 移除 product/list、
  product/detail,使拦截器真正执行这两个路径。

验证:用户12(Enagic体系3) 可见商品7/22/29(33个);游客/非体系用户仍30个
(不含vendor商品);无效token匿名降级200;商品22 detail 正常。
Xiaogang Liao 1 săptămână în urmă
părinte
comite
fd3addaf31

+ 17 - 1
cfc-backend/src/main/java/com/etotem/cfc/config/JwtInterceptor.java

@@ -113,11 +113,17 @@ private static final String[] PUBLIC_PATHS = {
         SecurityContextHolder.clearContext();
 
         String path = request.getRequestURI();
+        // 公开路径标记:不提前返回,改为“携有效 token 则解析用户上下文,否则匿名放行”。
+        // 修复:商品列表等公开接口此前永远拿不到 userId(白名单短路直接 return),
+        // 导致登录用户被当作游客处理,供应商体系可见性(vendor_visible=1 同体系内可见)
+        // 对登录用户失效(如 Enagic 体系成员看不到本体系 vendor 商品)。
+        boolean isPublicPath = false;
         for (String publicPath : PUBLIC_PATHS) {
             String boundaryPath = publicPath.endsWith("/**")
                     ? publicPath.substring(0, publicPath.length() - 3) : publicPath;
             if (path.equals(publicPath) || path.startsWith(boundaryPath + "/")) {
-                return true;
+                isPublicPath = true;
+                break;
             }
         }
 
@@ -144,6 +150,11 @@ private static final String[] PUBLIC_PATHS = {
                 writeUnauthorized(response);
                 return false;
             }
+            if (isPublicPath) {
+                // 公开路径无 token:保持原行为(不设置 userId,控制器取 null),放行匿名浏览
+                log.debug("请求 {} 公开路径无Token,匿名放行", path);
+                return true;
+            }
             log.debug("请求 {} 无Token,设为匿名用户", path);
             setAnonymousUser(request);
             setAnonymousSecurityContext();
@@ -235,6 +246,11 @@ private static final String[] PUBLIC_PATHS = {
 
             return true;
         } catch (Exception e) {
+            if (isPublicPath) {
+                // 公开路径 token 无效/过期:不 401,降级匿名放行,保持游客可浏览
+                log.warn("公开路径token无效, 降级匿名放行: path={}, error={}", path, e.getMessage());
+                return true;
+            }
             // Token 无效/过期一律 401(不区分 loginRequired):
             // 避免前端带残留 token 时被静默降级为匿名,导致需登录接口返回
             // "请先登录"(code=500) 而前端仍认为已登录。前端收到 401 后

+ 0 - 2
cfc-backend/src/main/java/com/etotem/cfc/config/WebConfig.java

@@ -110,8 +110,6 @@ public class WebConfig implements WebMvcConfigurer {
                 "/api/admin-auth/account-roles",
                 "/api/admin-auth/wechat-scan-qr",
                 "/api/admin-auth/wechat-scan-poll",
-                "/api/product/list",
-                "/api/product/detail",
                 "/api/special-price/info",
                 "/api/product/type-list",
                 "/api/product/related-products",