From 732bb13f4797141733fe384affb5104ca32fb58d Mon Sep 17 00:00:00 2001 From: matevip Date: Sun, 5 Apr 2026 18:20:40 +0800 Subject: [PATCH] fix(security): resolve SPA frontend route refresh returning 401 --- .../java/vip/mate/config/SecurityConfig.java | 34 ++++++------------- .../vip/mate/config/SpaForwardController.java | 26 ++++++++++++++ 2 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 mateclaw-server/src/main/java/vip/mate/config/SpaForwardController.java diff --git a/mateclaw-server/src/main/java/vip/mate/config/SecurityConfig.java b/mateclaw-server/src/main/java/vip/mate/config/SecurityConfig.java index 524aaa8a..09bcae73 100644 --- a/mateclaw-server/src/main/java/vip/mate/config/SecurityConfig.java +++ b/mateclaw-server/src/main/java/vip/mate/config/SecurityConfig.java @@ -48,34 +48,20 @@ public class SecurityConfig { ) .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth - // 公开接口 + // 公开 API 接口 .requestMatchers( "/api/v1/auth/login", "/api/v1/settings/language", - "/swagger-ui.html", - "/swagger-ui/**", - "/v3/api-docs/**", - "/webjars/**", - "/actuator/**", - "/h2-console/**", - // 静态资源(前端 SPA) - "/", - "/index.html", - "/assets/**", - "/icons/**", - "/logo/**", - "/favicon.ico" + "/api/v1/agents/*/chat/stream", + "/api/v1/chat/stream", + "/api/v1/chat/*/stop", + "/api/v1/setup/**", + "/api/v1/channels/webhook/**" ).permitAll() - // SSE 流式接口允许匿名(开发模式,生产环境可改为 authenticated) - .requestMatchers("/api/v1/agents/*/chat/stream").permitAll() - .requestMatchers("/api/v1/chat/stream").permitAll() - .requestMatchers("/api/v1/chat/*/stop").permitAll() - // 初始化 Setup API(首次安装语言选择,无需认证) - .requestMatchers("/api/v1/setup/**").permitAll() - // 渠道 Webhook 回调(各平台消息推送,由平台签名机制保障安全) - .requestMatchers("/api/v1/channels/webhook/**").permitAll() - // 其余接口需要认证 - .anyRequest().authenticated() + // 所有其他 API 接口需要认证 + .requestMatchers("/api/**").authenticated() + // 非 API 请求(前端路由、静态资源、Swagger、H2 Console 等)全部放行 + .anyRequest().permitAll() ) .exceptionHandling(ex -> ex .authenticationEntryPoint((request, response, authException) -> { diff --git a/mateclaw-server/src/main/java/vip/mate/config/SpaForwardController.java b/mateclaw-server/src/main/java/vip/mate/config/SpaForwardController.java new file mode 100644 index 00000000..2a9e8f9d --- /dev/null +++ b/mateclaw-server/src/main/java/vip/mate/config/SpaForwardController.java @@ -0,0 +1,26 @@ +package vip.mate.config; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * SPA 前端路由 Fallback + *

+ * 将不含扩展名的 GET 请求转发到 index.html,由 Vue Router 接管客户端路由。 + * 路径段正则 {@code [^\\.]*} 排除含 "." 的路径(静态资源如 .js/.css/.ico), + * 同时 Spring MVC 会优先匹配 @RestController 精确路由,因此不会影响 /api/** 接口。 + * + * @author MateClaw Team + */ +@Controller +public class SpaForwardController { + + @GetMapping(value = { + "/{path:[^\\.]*}", + "/{path1:[^\\.]*}/{path2:[^\\.]*}", + "/{path1:[^\\.]*}/{path2:[^\\.]*}/{path3:[^\\.]*}" + }) + public String forward() { + return "forward:/index.html"; + } +}