|
@@ -1,170 +1,172 @@
|
|
|
-package com.etotem.cfc.config;
|
|
|
|
|
-
|
|
|
|
|
-import org.slf4j.Logger;
|
|
|
|
|
-import org.slf4j.LoggerFactory;
|
|
|
|
|
-import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
-import org.springframework.context.annotation.Bean;
|
|
|
|
|
-import org.springframework.context.annotation.Configuration;
|
|
|
|
|
-import org.springframework.core.Ordered;
|
|
|
|
|
-import org.springframework.core.annotation.Order;
|
|
|
|
|
-import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
|
|
|
|
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
|
|
|
-import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
|
|
|
|
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
|
|
|
-
|
|
|
|
|
-import javax.annotation.Resource;
|
|
|
|
|
-import javax.servlet.*;
|
|
|
|
|
-import javax.servlet.http.HttpServletRequest;
|
|
|
|
|
-import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
-import java.io.IOException;
|
|
|
|
|
-
|
|
|
|
|
-@Configuration
|
|
|
|
|
-public class WebConfig implements WebMvcConfigurer {
|
|
|
|
|
-
|
|
|
|
|
- private static final Logger log = LoggerFactory.getLogger(WebConfig.class);
|
|
|
|
|
-
|
|
|
|
|
- @Resource
|
|
|
|
|
- private JwtInterceptor jwtInterceptor;
|
|
|
|
|
-
|
|
|
|
|
- @Resource
|
|
|
|
|
- private FamilyAccessInterceptor familyAccessInterceptor;
|
|
|
|
|
-
|
|
|
|
|
- @Resource
|
|
|
|
|
- private OperationLogInterceptor operationLogInterceptor;
|
|
|
|
|
-
|
|
|
|
|
- @Resource
|
|
|
|
|
- private RateLimitInterceptor rateLimitInterceptor;
|
|
|
|
|
-
|
|
|
|
|
- @Value("${upload.base-dir:/data/cfc-uploads}")
|
|
|
|
|
- private String uploadBaseDir;
|
|
|
|
|
-
|
|
|
|
|
- @Value("${storage.type:local}")
|
|
|
|
|
- private String storageType;
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public void addCorsMappings(CorsRegistry registry) {
|
|
|
|
|
- registry.addMapping("/**")
|
|
|
|
|
- .allowedOriginPatterns("https://cfc.etotem.com.cn", "http://cfc.etotem.com.cn", "https://www.etotem.com.cn", "http://www.etotem.com.cn", "https://cf-club.iwintrue.com", "http://cf-club.iwintrue.com", "https://www.cf-club.com", "http://www.cf-club.com", "https://cfc.cf-club.com", "http://cfc.cf-club.com", "https://111.228.6.214", "http://111.228.6.214", "http://localhost:*", "http://127.0.0.1:*")
|
|
|
|
|
- .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
|
|
|
|
- .allowedHeaders("*")
|
|
|
|
|
- .allowCredentials(true)
|
|
|
|
|
- .maxAge(3600);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /** Chrome Private Network Access: allow requests from non-secure contexts to private-network backend */
|
|
|
|
|
- @Bean
|
|
|
|
|
- @Order(Ordered.HIGHEST_PRECEDENCE)
|
|
|
|
|
- public Filter privateNetworkAccessFilter() {
|
|
|
|
|
- return new Filter() {
|
|
|
|
|
- @Override
|
|
|
|
|
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
|
|
|
|
- throws IOException, ServletException {
|
|
|
|
|
- HttpServletRequest req = (HttpServletRequest) request;
|
|
|
|
|
- HttpServletResponse resp = (HttpServletResponse) response;
|
|
|
|
|
- resp.setHeader("Access-Control-Allow-Private-Network", "true");
|
|
|
|
|
- chain.doFilter(request, response);
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /** 诊断过滤器:记录所有请求的来源和状态码 */
|
|
|
|
|
- @Bean
|
|
|
|
|
- @Order(Ordered.HIGHEST_PRECEDENCE + 1)
|
|
|
|
|
- public Filter diagnosticFilter() {
|
|
|
|
|
- return new Filter() {
|
|
|
|
|
- @Override
|
|
|
|
|
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
|
|
|
|
- throws IOException, ServletException {
|
|
|
|
|
- HttpServletRequest req = (HttpServletRequest) request;
|
|
|
|
|
- long start = System.currentTimeMillis();
|
|
|
|
|
- chain.doFilter(request, response);
|
|
|
|
|
- int status = ((HttpServletResponse) response).getStatus();
|
|
|
|
|
- long ms = System.currentTimeMillis() - start;
|
|
|
|
|
- if (status == 403 || req.getRequestURI().contains("/api/payment")) {
|
|
|
|
|
- log.warn("[DIAG] {} {} -> {} ({}ms) origin={} ua={}",
|
|
|
|
|
- req.getMethod(), req.getRequestURI(), status, ms,
|
|
|
|
|
- req.getHeader("Origin"),
|
|
|
|
|
- req.getHeader("User-Agent"));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public void addInterceptors(InterceptorRegistry registry) {
|
|
|
|
|
- registry.addInterceptor(jwtInterceptor)
|
|
|
|
|
- .addPathPatterns("/api/**")
|
|
|
|
|
- .excludePathPatterns(
|
|
|
|
|
- "/api/auth/send-code",
|
|
|
|
|
- "/api/auth/phone-login",
|
|
|
|
|
- "/api/auth/wechat-login",
|
|
|
|
|
- "/api/auth/wechat-phone-login",
|
|
|
|
|
- "/api/auth/check-phone",
|
|
|
|
|
- "/api/auth/direct-register",
|
|
|
|
|
- "/api/auth/register-with-idcard",
|
|
|
|
|
- "/api/admin-auth/send-code",
|
|
|
|
|
- "/api/admin-auth/login",
|
|
|
|
|
- "/api/admin-auth/login-by-password",
|
|
|
|
|
- "/api/product/list",
|
|
|
|
|
- "/api/product/detail",
|
|
|
|
|
- "/api/product/type-list",
|
|
|
|
|
- "/api/mini-game/list",
|
|
|
|
|
- "/api/articles/list",
|
|
|
|
|
- "/api/articles/detail",
|
|
|
|
|
- "/api/articles/categories",
|
|
|
|
|
- "/api/articles/featured",
|
|
|
|
|
- "/api/articles/record-read",
|
|
|
|
|
- "/api/articles/updated-since",
|
|
|
|
|
- "/api/activity/list",
|
|
|
|
|
- "/api/activity/detail",
|
|
|
|
|
- "/api/ai/context",
|
|
|
|
|
- "/api/config/public/**",
|
|
|
|
|
- "/api/payment/wechat/native",
|
|
|
|
|
- "/api/payment/wechat/create",
|
|
|
|
|
- "/api/payment/wechat/status",
|
|
|
|
|
- "/api/payment/wechat/oauth2-url",
|
|
|
|
|
- "/api/payment/wechat/oauth2-callback"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- registry.addInterceptor(operationLogInterceptor)
|
|
|
|
|
- .addPathPatterns("/api/**");
|
|
|
|
|
-
|
|
|
|
|
- registry.addInterceptor(rateLimitInterceptor)
|
|
|
|
|
- .addPathPatterns("/api/**");
|
|
|
|
|
-
|
|
|
|
|
- registry.addInterceptor(familyAccessInterceptor)
|
|
|
|
|
- .addPathPatterns("/api/**")
|
|
|
|
|
- .excludePathPatterns(
|
|
|
|
|
- "/api/auth/send-code",
|
|
|
|
|
- "/api/auth/phone-login",
|
|
|
|
|
- "/api/auth/wechat-login",
|
|
|
|
|
- "/api/auth/wechat-phone-login",
|
|
|
|
|
- "/api/auth/check-phone",
|
|
|
|
|
- "/api/auth/direct-register",
|
|
|
|
|
- "/api/auth/register-with-idcard",
|
|
|
|
|
- "/api/admin-auth/send-code",
|
|
|
|
|
- "/api/admin-auth/login",
|
|
|
|
|
- "/api/admin-auth/login-by-password",
|
|
|
|
|
- "/api/product/list",
|
|
|
|
|
- "/api/product/detail",
|
|
|
|
|
- "/api/product/type-list",
|
|
|
|
|
- "/api/mini-game/list",
|
|
|
|
|
- "/api/articles/list",
|
|
|
|
|
- "/api/articles/detail",
|
|
|
|
|
- "/api/articles/categories",
|
|
|
|
|
- "/api/articles/featured",
|
|
|
|
|
- "/api/articles/record-read",
|
|
|
|
|
- "/api/activity/list",
|
|
|
|
|
- "/api/activity/detail"
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Override
|
|
|
|
|
- public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
|
|
|
|
- // 仅在本地存储模式下注册静态资源映射;jdcloud 模式文件走京东云公网URL
|
|
|
|
|
- if ("local".equals(storageType)) {
|
|
|
|
|
- registry.addResourceHandler("/uploads/**")
|
|
|
|
|
- .addResourceLocations("file:" + uploadBaseDir + "/");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+package com.etotem.cfc.config;
|
|
|
|
|
+
|
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
+import org.springframework.context.annotation.Bean;
|
|
|
|
|
+import org.springframework.context.annotation.Configuration;
|
|
|
|
|
+import org.springframework.core.Ordered;
|
|
|
|
|
+import org.springframework.core.annotation.Order;
|
|
|
|
|
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
|
|
|
|
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
|
|
|
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
|
|
|
|
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
|
|
|
+
|
|
|
|
|
+import javax.annotation.Resource;
|
|
|
|
|
+import javax.servlet.*;
|
|
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
+import java.io.IOException;
|
|
|
|
|
+
|
|
|
|
|
+@Configuration
|
|
|
|
|
+public class WebConfig implements WebMvcConfigurer {
|
|
|
|
|
+
|
|
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(WebConfig.class);
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private JwtInterceptor jwtInterceptor;
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private FamilyAccessInterceptor familyAccessInterceptor;
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private OperationLogInterceptor operationLogInterceptor;
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private RateLimitInterceptor rateLimitInterceptor;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${upload.base-dir:/data/cfc-uploads}")
|
|
|
|
|
+ private String uploadBaseDir;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${storage.type:local}")
|
|
|
|
|
+ private String storageType;
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void addCorsMappings(CorsRegistry registry) {
|
|
|
|
|
+ registry.addMapping("/**")
|
|
|
|
|
+ .allowedOriginPatterns("https://cfc.etotem.com.cn", "http://cfc.etotem.com.cn", "https://www.etotem.com.cn", "http://www.etotem.com.cn", "https://cf-club.iwintrue.com", "http://cf-club.iwintrue.com", "https://www.cf-club.com", "http://www.cf-club.com", "https://cfc.cf-club.com", "http://cfc.cf-club.com", "https://111.228.6.214", "http://111.228.6.214", "http://localhost:*", "http://127.0.0.1:*")
|
|
|
|
|
+ .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
|
|
|
|
+ .allowedHeaders("*")
|
|
|
|
|
+ .allowCredentials(true)
|
|
|
|
|
+ .maxAge(3600);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** Chrome Private Network Access: allow requests from non-secure contexts to private-network backend */
|
|
|
|
|
+ @Bean
|
|
|
|
|
+ @Order(Ordered.HIGHEST_PRECEDENCE)
|
|
|
|
|
+ public Filter privateNetworkAccessFilter() {
|
|
|
|
|
+ return new Filter() {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
|
|
|
|
+ throws IOException, ServletException {
|
|
|
|
|
+ HttpServletRequest req = (HttpServletRequest) request;
|
|
|
|
|
+ HttpServletResponse resp = (HttpServletResponse) response;
|
|
|
|
|
+ resp.setHeader("Access-Control-Allow-Private-Network", "true");
|
|
|
|
|
+ chain.doFilter(request, response);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 诊断过滤器:记录所有请求的来源和状态码 */
|
|
|
|
|
+ @Bean
|
|
|
|
|
+ @Order(Ordered.HIGHEST_PRECEDENCE + 1)
|
|
|
|
|
+ public Filter diagnosticFilter() {
|
|
|
|
|
+ return new Filter() {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
|
|
|
|
+ throws IOException, ServletException {
|
|
|
|
|
+ HttpServletRequest req = (HttpServletRequest) request;
|
|
|
|
|
+ long start = System.currentTimeMillis();
|
|
|
|
|
+ chain.doFilter(request, response);
|
|
|
|
|
+ int status = ((HttpServletResponse) response).getStatus();
|
|
|
|
|
+ long ms = System.currentTimeMillis() - start;
|
|
|
|
|
+ if (status == 403 || req.getRequestURI().contains("/api/payment")) {
|
|
|
|
|
+ log.warn("[DIAG] {} {} -> {} ({}ms) origin={} ua={}",
|
|
|
|
|
+ req.getMethod(), req.getRequestURI(), status, ms,
|
|
|
|
|
+ req.getHeader("Origin"),
|
|
|
|
|
+ req.getHeader("User-Agent"));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void addInterceptors(InterceptorRegistry registry) {
|
|
|
|
|
+ registry.addInterceptor(jwtInterceptor)
|
|
|
|
|
+ .addPathPatterns("/api/**")
|
|
|
|
|
+ .excludePathPatterns(
|
|
|
|
|
+ "/api/auth/send-code",
|
|
|
|
|
+ "/api/auth/phone-login",
|
|
|
|
|
+ "/api/auth/wechat-login",
|
|
|
|
|
+ "/api/auth/wechat-phone-login",
|
|
|
|
|
+ "/api/auth/check-phone",
|
|
|
|
|
+ "/api/auth/direct-register",
|
|
|
|
|
+ "/api/auth/register-with-idcard",
|
|
|
|
|
+ "/api/admin-auth/send-code",
|
|
|
|
|
+ "/api/admin-auth/login",
|
|
|
|
|
+ "/api/admin-auth/login-by-password",
|
|
|
|
|
+ "/api/product/list",
|
|
|
|
|
+ "/api/product/detail",
|
|
|
|
|
+ "/api/product/type-list",
|
|
|
|
|
+ "/api/mini-game/list",
|
|
|
|
|
+ "/api/articles/list",
|
|
|
|
|
+ "/api/articles/detail",
|
|
|
|
|
+ "/api/articles/categories",
|
|
|
|
|
+ "/api/articles/featured",
|
|
|
|
|
+ "/api/articles/record-read",
|
|
|
|
|
+ "/api/growth/**",
|
|
|
|
|
+ "/api/articles/updated-since",
|
|
|
|
|
+ "/api/activity/list",
|
|
|
|
|
+ "/api/activity/detail",
|
|
|
|
|
+ "/api/ai/context",
|
|
|
|
|
+ "/api/config/public/**",
|
|
|
|
|
+ "/api/payment/wechat/native",
|
|
|
|
|
+ "/api/payment/wechat/create",
|
|
|
|
|
+ "/api/payment/wechat/status",
|
|
|
|
|
+ "/api/payment/wechat/oauth2-url",
|
|
|
|
|
+ "/api/payment/wechat/oauth2-callback"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ registry.addInterceptor(operationLogInterceptor)
|
|
|
|
|
+ .addPathPatterns("/api/**");
|
|
|
|
|
+
|
|
|
|
|
+ registry.addInterceptor(rateLimitInterceptor)
|
|
|
|
|
+ .addPathPatterns("/api/**");
|
|
|
|
|
+
|
|
|
|
|
+ registry.addInterceptor(familyAccessInterceptor)
|
|
|
|
|
+ .addPathPatterns("/api/**")
|
|
|
|
|
+ .excludePathPatterns(
|
|
|
|
|
+ "/api/auth/send-code",
|
|
|
|
|
+ "/api/auth/phone-login",
|
|
|
|
|
+ "/api/auth/wechat-login",
|
|
|
|
|
+ "/api/auth/wechat-phone-login",
|
|
|
|
|
+ "/api/auth/check-phone",
|
|
|
|
|
+ "/api/auth/direct-register",
|
|
|
|
|
+ "/api/auth/register-with-idcard",
|
|
|
|
|
+ "/api/admin-auth/send-code",
|
|
|
|
|
+ "/api/admin-auth/login",
|
|
|
|
|
+ "/api/admin-auth/login-by-password",
|
|
|
|
|
+ "/api/product/list",
|
|
|
|
|
+ "/api/product/detail",
|
|
|
|
|
+ "/api/product/type-list",
|
|
|
|
|
+ "/api/mini-game/list",
|
|
|
|
|
+ "/api/articles/list",
|
|
|
|
|
+ "/api/articles/detail",
|
|
|
|
|
+ "/api/articles/categories",
|
|
|
|
|
+ "/api/articles/featured",
|
|
|
|
|
+ "/api/articles/record-read",
|
|
|
|
|
+ "/api/growth/**",
|
|
|
|
|
+ "/api/activity/list",
|
|
|
|
|
+ "/api/activity/detail"
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
|
|
|
|
+ // 仅在本地存储模式下注册静态资源映射;jdcloud 模式文件走京东云公网URL
|
|
|
|
|
+ if ("local".equals(storageType)) {
|
|
|
|
|
+ registry.addResourceHandler("/uploads/**")
|
|
|
|
|
+ .addResourceLocations("file:" + uploadBaseDir + "/");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|