李学强 6 luni în urmă
părinte
comite
cf41043980
17 a modificat fișierele cu 430 adăugiri și 148 ștergeri
  1. 0 31
      lxq-admin/src/main/java/com/lxq/admin/biz/config/FilterConfig.java
  2. 0 27
      lxq-admin/src/main/java/com/lxq/admin/biz/config/SysLogConfiguration.java
  3. 1 1
      lxq-admin/src/main/java/com/lxq/admin/biz/controller/SysImageCodeController.java
  4. 0 55
      lxq-common/lxq-common-core/src/main/java/com/lxq/common/core/config/TaskExecutorConfiguration.java
  5. 4 2
      lxq-common/lxq-common-core/src/main/java/com/lxq/common/core/util/WebUtils.java
  6. 0 1
      lxq-common/lxq-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  7. 0 1
      lxq-common/lxq-common-log/src/main/java/com/lxq/common/log/LogAutoConfiguration.java
  8. 9 0
      lxq-system/pom.xml
  9. 35 0
      lxq-system/src/main/java/com/lxq/system/biz/config/AesConfigProperties.java
  10. 0 15
      lxq-system/src/main/java/com/lxq/system/biz/config/BeanConfigScanConfig.java
  11. 24 0
      lxq-system/src/main/java/com/lxq/system/biz/config/GatewayConfigProperties.java
  12. 81 0
      lxq-system/src/main/java/com/lxq/system/biz/config/SysConfigConfiguration.java
  13. 1 2
      lxq-system/src/main/java/com/lxq/system/biz/event/SysLogListener.java
  14. 250 0
      lxq-system/src/main/java/com/lxq/system/biz/filter/RequestDecoderFilter.java
  15. 11 12
      lxq-system/src/main/java/com/lxq/system/biz/filter/ValidateCodeGatewayFilter.java
  16. 1 1
      lxq-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  17. 13 0
      lxq-system/src/main/resources/application-dev.yml

+ 0 - 31
lxq-admin/src/main/java/com/lxq/admin/biz/config/FilterConfig.java

@@ -1,31 +0,0 @@
-package com.lxq.admin.biz.config;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.lxq.admin.biz.filter.ImageCodeFilter;
-import com.lxq.common.core.constant.SecurityConstants;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.data.redis.core.RedisTemplate;
-
-/**
- * 过滤器配置
- * @author lixueqiang
- */
-@Configuration
-public class FilterConfig {
-
-    @Value("${spring.profiles.active}")
-    private String active;
-
-    @Bean
-    public FilterRegistrationBean<ImageCodeFilter> imageCodeFilterRegistration(RedisTemplate<String, Object> redisTemplate, ObjectMapper objectMapper) {
-
-        FilterRegistrationBean<ImageCodeFilter> registration = new FilterRegistrationBean<>();
-        registration.setFilter(new ImageCodeFilter(redisTemplate, objectMapper, active));
-        registration.addUrlPatterns(SecurityConstants.OAUTH_TOKEN_URL);
-        registration.setOrder(Integer.MIN_VALUE);
-        return registration;
-    }
-}

+ 0 - 27
lxq-admin/src/main/java/com/lxq/admin/biz/config/SysLogConfiguration.java

@@ -1,27 +0,0 @@
-package com.lxq.admin.biz.config;
-
-import com.lxq.admin.biz.event.SysLogListener;
-import com.lxq.common.log.config.LxqLogProperties;
-import com.lxq.system.biz.service.SysLogService;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * 验证码路由器 webflux响应式编程
- *
- * @author 没秃顶的码农
- * @date 2023/11/04
- */
-@Slf4j
-@Configuration(proxyBeanMethods = false)
-@RequiredArgsConstructor
-public class SysLogConfiguration {
-
-	@Bean
-	public SysLogListener sysLogListener(SysLogService sysLogService, LxqLogProperties logProperties) {
-		return new SysLogListener(sysLogService, logProperties);
-	}
-
-}

+ 1 - 1
lxq-admin/src/main/java/com/lxq/admin/biz/controller/ImageCodeController.java → lxq-admin/src/main/java/com/lxq/admin/biz/controller/SysImageCodeController.java

@@ -29,7 +29,7 @@ import java.util.concurrent.TimeUnit;
 @RestController
 @RequestMapping("/code")
 @RequiredArgsConstructor
-public class ImageCodeController {
+public class SysImageCodeController {
 
     private final RedisTemplate<String, Object> redisTemplate;
 

+ 0 - 55
lxq-common/lxq-common-core/src/main/java/com/lxq/common/core/config/TaskExecutorConfiguration.java

@@ -1,55 +0,0 @@
-package com.lxq.common.core.config;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.context.annotation.Bean;
-import org.springframework.scheduling.annotation.AsyncConfigurer;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
-
-import java.util.Optional;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ThreadPoolExecutor;
-
-/**
- * @author 没秃顶的码农
- * @date 2022/5/20
- */
-@AutoConfiguration
-public class TaskExecutorConfiguration implements AsyncConfigurer {
-
-	/**
-	 * 获取当前机器的核数, 不一定准确 请根据实际场景 CPU密集 || IO 密集
-	 */
-	public static final int CPU_NUM = Runtime.getRuntime().availableProcessors();
-
-	@Value("${thread.pool.corePoolSize:}")
-	private Optional<Integer> corePoolSize;
-
-	@Value("${thread.pool.maxPoolSize:}")
-	private Optional<Integer> maxPoolSize;
-
-	@Value("${thread.pool.queueCapacity:}")
-	private Optional<Integer> queueCapacity;
-
-	@Value("${thread.pool.awaitTerminationSeconds:}")
-	private Optional<Integer> awaitTerminationSeconds;
-
-	@Override
-	@Bean
-	public Executor getAsyncExecutor() {
-		ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
-		// 核心线程大小 默认区 CPU 数量
-		taskExecutor.setCorePoolSize(corePoolSize.orElse(CPU_NUM));
-		// 最大线程大小 默认区 CPU * 2 数量
-		taskExecutor.setMaxPoolSize(maxPoolSize.orElse(CPU_NUM * 2));
-		// 队列最大容量
-		taskExecutor.setQueueCapacity(queueCapacity.orElse(500));
-		taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
-		taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
-		taskExecutor.setAwaitTerminationSeconds(awaitTerminationSeconds.orElse(60));
-		taskExecutor.setThreadNamePrefix("LKB-Thread-");
-		taskExecutor.initialize();
-		return taskExecutor;
-	}
-
-}

+ 4 - 2
lxq-common/lxq-common-core/src/main/java/com/lxq/common/core/util/WebUtils.java

@@ -3,6 +3,7 @@ package com.lxq.common.core.util;
 
 import cn.hutool.core.codec.Base64;
 import com.lxq.common.core.exception.CheckedException;
+import jakarta.servlet.ServletRequest;
 import jakarta.servlet.http.Cookie;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
@@ -114,8 +115,9 @@ public class WebUtils extends org.springframework.web.util.WebUtils {
 	 * @return
 	 */
 	@SneakyThrows
-	public String getClientId(ServerHttpRequest request) {
-		String header = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
+	public String getClientId(HttpServletRequest request) {
+
+		String header = request.getHeaders(HttpHeaders.AUTHORIZATION).nextElement();
 		return splitClient(header)[0];
 	}
 

+ 0 - 1
lxq-common/lxq-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -1,4 +1,3 @@
-com.lxq.common.core.config.TaskExecutorConfiguration
 com.lxq.common.core.config.RedisTemplateConfiguration
 com.lxq.common.core.config.RestTemplateConfiguration
 com.lxq.common.core.util.SpringContextHolder

+ 0 - 1
lxq-common/lxq-common-log/src/main/java/com/lxq/common/log/LogAutoConfiguration.java

@@ -20,7 +20,6 @@ import org.springframework.scheduling.annotation.EnableAsync;
 @ConditionalOnProperty(value = "security.log.enabled", matchIfMissing = true)
 public class LogAutoConfiguration {
 
-
 	@Bean
 	public SysLogAspect sysLogAspect() {
 		return new SysLogAspect();

+ 9 - 0
lxq-system/pom.xml

@@ -68,5 +68,14 @@
             <groupId>com.lxq</groupId>
             <artifactId>lxq-common-mybatis</artifactId>
         </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-crypto</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15to18</artifactId>
+            <version>1.68</version>
+        </dependency>
     </dependencies>
 </project>

+ 35 - 0
lxq-system/src/main/java/com/lxq/system/biz/config/AesConfigProperties.java

@@ -0,0 +1,35 @@
+package com.lxq.system.biz.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+
+/**
+ * @author LXQ
+ * @date 2021/10/4
+ * <p>
+ * 网关配置文件
+ */
+@Data
+@ConfigurationProperties("gateway.aes")
+public class AesConfigProperties {
+
+	private Boolean enabled = true;
+
+	private String encodeKey;
+
+	private String encodeIv;
+
+	private String encodeMode;
+
+	private String encodePadding;
+
+
+	/**
+	 * 需要过滤不解密的接口
+	 */
+	private List<String> filterUrl;
+
+}

+ 0 - 15
lxq-system/src/main/java/com/lxq/system/biz/config/BeanConfigScanConfig.java

@@ -1,15 +0,0 @@
-package com.lxq.system.biz.config;
-
-import org.mybatis.spring.annotation.MapperScan;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-
-
-/**
- * @author lixueqiang
- */
-@ComponentScan(basePackages = "com.lxq.system")
-@MapperScan(basePackages = "com.lxq.system.biz.mapper")
-@Configuration
-public class BeanConfigScanConfig{
-}

+ 24 - 0
lxq-system/src/main/java/com/lxq/system/biz/config/GatewayConfigProperties.java

@@ -0,0 +1,24 @@
+package com.lxq.system.biz.config;
+
+import com.lxq.system.biz.filter.ValidateCodeGatewayFilter;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+/**
+ * @author LXQ
+ * @date 2021/10/4
+ * <p>
+ * 网关配置文件
+ */
+@Data
+@ConfigurationProperties("gateway")
+public class GatewayConfigProperties {
+
+	/**
+	 * 网关不需要校验验证码的客户端 {@link ValidateCodeGatewayFilter}
+	 */
+	private List<String> ignoreClients;
+
+}

+ 81 - 0
lxq-system/src/main/java/com/lxq/system/biz/config/SysConfigConfiguration.java

@@ -0,0 +1,81 @@
+package com.lxq.system.biz.config;
+
+import cn.hutool.crypto.symmetric.AES;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.lxq.common.core.constant.SecurityConstants;
+import com.lxq.common.log.config.LxqLogProperties;
+import com.lxq.system.biz.event.SysLogListener;
+import com.lxq.system.biz.filter.ValidateCodeGatewayFilter;
+import com.lxq.system.biz.filter.RequestDecoderFilter;
+import com.lxq.system.biz.service.SysLogService;
+import lombok.RequiredArgsConstructor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.data.redis.core.RedisTemplate;
+
+
+/**
+ * @author lixueqiang
+ */
+@ComponentScan(basePackages = "com.lxq.system")
+@MapperScan(basePackages = "com.lxq.system.biz.mapper")
+@EnableConfigurationProperties({AesConfigProperties.class, GatewayConfigProperties.class})
+@RequiredArgsConstructor
+public class SysConfigConfiguration {
+
+    private final AesConfigProperties aesConfigProperties;
+
+    private final GatewayConfigProperties gatewayConfigProperties;
+
+
+    @Bean
+    public SysLogListener sysLogListener(SysLogService sysLogService, LxqLogProperties logProperties) {
+        return new SysLogListener(sysLogService, logProperties);
+    }
+
+    @Bean
+    public FilterRegistrationBean<ValidateCodeGatewayFilter> imageCodeFilterRegistration(RedisTemplate<String, Object> redisTemplate, ObjectMapper objectMapper) {
+
+        FilterRegistrationBean<ValidateCodeGatewayFilter> registration = new FilterRegistrationBean<>();
+        registration.setFilter(new ValidateCodeGatewayFilter(redisTemplate, objectMapper, gatewayConfigProperties));
+        registration.addUrlPatterns(SecurityConstants.OAUTH_TOKEN_URL);
+        registration.setOrder(Integer.MIN_VALUE);
+        return registration;
+    }
+
+    /**
+     * 加解密过滤器
+     */
+    @Bean
+    @ConditionalOnProperty(name = "gateway.aes.enabled", matchIfMissing = true)
+    @DependsOn("cryptoAes")
+    public FilterRegistrationBean<RequestDecoderFilter> requestDecoderFilterRegistration(AES cryptoAes, ObjectMapper objectMapper) {
+
+        FilterRegistrationBean<RequestDecoderFilter> registration = new FilterRegistrationBean<>();
+        registration.setFilter(new RequestDecoderFilter(cryptoAes, objectMapper, aesConfigProperties));
+        registration.addUrlPatterns("/*");
+        registration.setOrder(Integer.MIN_VALUE + 1);
+        return registration;
+    }
+
+    /**
+     * <p>
+     * aes加密配置 此处设在配置类可以避免每次请求都去创建加密类,以此节约性能
+     * </p>
+     * @return {@link AES}
+     */
+    @Bean
+    public AES cryptoAes() {
+        return new AES(aesConfigProperties.getEncodeMode(), aesConfigProperties.getEncodePadding(),
+                // 密钥,可以自定义
+                aesConfigProperties.getEncodeKey().getBytes(),
+                // iv加盐,按照实际需求添加
+                aesConfigProperties.getEncodeIv().getBytes());
+    }
+}

+ 1 - 2
lxq-admin/src/main/java/com/lxq/admin/biz/event/SysLogListener.java → lxq-system/src/main/java/com/lxq/system/biz/event/SysLogListener.java

@@ -1,4 +1,4 @@
-package com.lxq.admin.biz.event;
+package com.lxq.system.biz.event;
 
 import cn.hutool.core.text.CharSequenceUtil;
 import com.fasterxml.jackson.annotation.JsonFilter;
@@ -20,7 +20,6 @@ import org.springframework.beans.factory.InitializingBean;
 import org.springframework.context.event.EventListener;
 import org.springframework.core.annotation.Order;
 import org.springframework.scheduling.annotation.Async;
-import org.springframework.stereotype.Component;
 
 import java.util.Objects;
 

+ 250 - 0
lxq-system/src/main/java/com/lxq/system/biz/filter/RequestDecoderFilter.java

@@ -0,0 +1,250 @@
+package com.lxq.system.biz.filter;
+
+import cn.hutool.crypto.symmetric.AES;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.lxq.common.core.exception.AesDecodeException;
+import com.lxq.common.core.util.R;
+import com.lxq.system.biz.config.AesConfigProperties;
+import io.netty.util.CharsetUtil;
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.util.PathMatcher;
+import org.springframework.util.StringUtils;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 请求解密过滤器
+ *
+ * @author lixueqiang
+ * @date 2026/01/09
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class RequestDecoderFilter implements Filter {
+
+    private final AES cryptoAes;
+
+    private final ObjectMapper objectMapper;
+
+    private final AesConfigProperties aesConfigProperties;
+
+    private static final PathMatcher PATH_MATCHER = new AntPathMatcher();
+
+    private static final Pattern DELETE_PATH_PATTERN = Pattern.compile("(.+/)[^/]+$");
+
+    private static final List<String> FILE_TYPES = List.of("multipart/form-data");
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        HttpServletRequest httpRequest = (HttpServletRequest) request;
+        HttpServletResponse httpResponse = (HttpServletResponse) response;
+        String method = httpRequest.getMethod();
+
+
+        String requestURI = httpRequest.getServletPath();
+        //过滤接口不解密
+        if (!aesConfigProperties.getFilterUrl().isEmpty() && aesConfigProperties.getFilterUrl().contains(requestURI)) {
+            chain.doFilter(request, response);
+            return;
+        }
+        boolean match = aesConfigProperties.getFilterUrl().stream().anyMatch(url -> PATH_MATCHER.match(url, requestURI));
+        if (match) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        String contentType = httpRequest.getContentType();
+        if (StringUtils.hasText(contentType) && FILE_TYPES.stream().anyMatch(contentType::startsWith)) {
+            // 这是一个文件请求
+            chain.doFilter(request, response);
+            return;
+        }
+        try {
+            if ("GET".equalsIgnoreCase(method)) {
+                request = decryptGetRequest(httpRequest);
+            } else if ("DELETE".equalsIgnoreCase(method)) {
+                request = decryptDeleteRequest(httpRequest);
+            } else if ("POST".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method)) {
+                request = decryptJsonBody(httpRequest);
+            }
+            chain.doFilter(request, response);
+        } catch (AesDecodeException e) {
+            log.error("AES解密失败: {}", e.getMessage(), e);
+            handleException("解密失败", httpResponse);
+        }
+    }
+
+    private HttpServletRequest decryptGetRequest(HttpServletRequest request) {
+
+        try {
+            String encryptedValue = request.getParameter("value");
+            if (encryptedValue != null) {
+                byte[] decode = Base64.getMimeDecoder().decode(encryptedValue);
+                String decryptedValue = cryptoAes.decryptStr(new String(decode));
+                request = new ParameterDecodedRequest(request, decryptedValue);
+            }
+            return request;
+        } catch (Exception e) {
+            throw new AesDecodeException(e.getMessage());
+        }
+    }
+
+    private HttpServletRequest decryptDeleteRequest(HttpServletRequest request) {
+        try {
+            String requestURI = request.getRequestURI();
+            String[] pathSegments = requestURI.split("/");
+            String encryptedValue = pathSegments[pathSegments.length - 1];
+
+            byte[] decode = Base64.getMimeDecoder().decode(encryptedValue);
+            String decryptedValue = cryptoAes.decryptStr(new String(decode));
+
+            Matcher matcher = DELETE_PATH_PATTERN.matcher(requestURI);
+            if (matcher.find()) {
+                String lastSegment = matcher.group(1);
+                String newURI = lastSegment + decryptedValue;
+                request = new PathDecodedRequest(request, newURI, decryptedValue);
+            }
+
+
+//            Matcher matcher = DELETE_PATH_PATTERN.matcher(requestURI);
+//            if (matcher.find()) {
+//                String encryptedValue = matcher.group(2);
+//                String newURI = requestURI.replace("{" + encryptedValue + "}", decryptedValue);
+//                request = new PathDecodedRequest(request, newURI, decryptedValue);
+//            }
+            return request;
+        } catch (Exception e) {
+            throw new AesDecodeException(e.getMessage());
+        }
+    }
+
+    private HttpServletRequest decryptJsonBody(HttpServletRequest request) {
+        try {
+            byte[] rawData = IOUtils.toByteArray(request.getInputStream());
+            String encryptedJson = new String(rawData, StandardCharsets.UTF_8);
+            byte[] decode = Base64.getMimeDecoder().decode(encryptedJson);
+            String decryptedJson = cryptoAes.decryptStr(new String(decode));
+            byte[] decryptedBody = decryptedJson.getBytes(StandardCharsets.UTF_8);
+            return new CachedBodyHttpServletRequestWrapper(request, decryptedBody);
+        } catch (Exception e) {
+            throw new AesDecodeException(e.getMessage());
+        }
+    }
+
+    static class CachedBodyHttpServletRequestWrapper extends HttpServletRequestWrapper {
+        private final byte[] cachedBody;
+
+        public CachedBodyHttpServletRequestWrapper(HttpServletRequest request, byte[] cachedBody) {
+            super(request);
+            this.cachedBody = cachedBody;
+        }
+
+        @Override
+        public ServletInputStream getInputStream() {
+            return new CachedBodyServletInputStream(cachedBody);
+        }
+
+        @Override
+        public BufferedReader getReader() {
+            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(cachedBody);
+            return new BufferedReader(new InputStreamReader(byteArrayInputStream, StandardCharsets.UTF_8));
+        }
+    }
+
+    static class CachedBodyServletInputStream extends ServletInputStream {
+        private final ByteArrayInputStream inputStream;
+
+        public CachedBodyServletInputStream(byte[] cachedBody) {
+            this.inputStream = new ByteArrayInputStream(cachedBody);
+        }
+
+        @Override
+        public boolean isFinished() {
+            return inputStream.available() == 0;
+        }
+
+        @Override
+        public boolean isReady() {
+            return true;
+        }
+
+        @Override
+        public void setReadListener(ReadListener listener) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int read() {
+            return inputStream.read();
+        }
+    }
+
+    static class ParameterDecodedRequest extends HttpServletRequestWrapper {
+        private final String decryptedValue;
+
+        public ParameterDecodedRequest(HttpServletRequest request, String decryptedValue) {
+            super(request);
+            this.decryptedValue = decryptedValue;
+        }
+
+        @Override
+        public String getParameter(String name) {
+            if ("value".equals(name)) {
+                return decryptedValue;
+            }
+            return super.getParameter(name);
+        }
+    }
+
+    static class PathDecodedRequest extends HttpServletRequestWrapper {
+        private final String newURI;
+        private final String decryptedValue;
+
+        public PathDecodedRequest(HttpServletRequest request, String newURI, String decryptedValue) {
+            super(request);
+            this.newURI = newURI;
+            this.decryptedValue = decryptedValue;
+        }
+
+        @Override
+        public String getRequestURI() {
+            return newURI;
+        }
+
+        @Override
+        public String getServletPath() {
+            return newURI;
+        }
+
+        @Override
+        public String getParameter(String name) {
+            if ("value".equals(name)) {
+                return decryptedValue;
+            }
+            return super.getParameter(name);
+        }
+    }
+
+    private void handleException(String ex, HttpServletResponse response) throws IOException {
+
+        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+        response.setCharacterEncoding(CharsetUtil.UTF_8.name());
+        response.getWriter().write(objectMapper.writeValueAsString(R.failed(ex)));
+    }
+}

+ 11 - 12
lxq-admin/src/main/java/com/lxq/admin/biz/filter/ImageCodeFilter.java → lxq-system/src/main/java/com/lxq/system/biz/filter/ValidateCodeGatewayFilter.java

@@ -1,4 +1,4 @@
-package com.lxq.admin.biz.filter;
+package com.lxq.system.biz.filter;
 
 import cn.hutool.core.text.CharSequenceUtil;
 import cn.hutool.core.util.ObjectUtil;
@@ -8,6 +8,8 @@ import com.lxq.common.core.constant.SecurityConstants;
 import com.lxq.common.core.constant.enums.ErrorTypeEnum;
 import com.lxq.common.core.exception.ValidateCodeException;
 import com.lxq.common.core.util.R;
+import com.lxq.common.core.util.WebUtils;
+import com.lxq.system.biz.config.GatewayConfigProperties;
 import io.netty.util.CharsetUtil;
 import jakarta.servlet.*;
 import jakarta.servlet.http.HttpServletRequest;
@@ -15,11 +17,8 @@ import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.http.Header;
-import org.apache.http.entity.ContentType;
-import org.apache.tomcat.util.http.HeaderUtil;
 import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.http.MediaType;
+import org.springframework.http.server.reactive.ServerHttpRequest;
 
 import java.io.IOException;
 import java.util.Objects;
@@ -30,29 +29,29 @@ import java.util.Objects;
  */
 @Slf4j
 @RequiredArgsConstructor
-public class ImageCodeFilter implements Filter {
+public class ValidateCodeGatewayFilter implements Filter {
 
     private final RedisTemplate<String, Object> redisTemplate;
 
     private final ObjectMapper objectMapper;
 
-    private final String active;
+    private final GatewayConfigProperties configProperties;
 
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
             throws IOException, ServletException {
         HttpServletRequest httpRequest = (HttpServletRequest) request;
         HttpServletResponse httpResponse = (HttpServletResponse) response;
-//        if("dev".equals(active) || "test".equals(active)){
-//            chain.doFilter(request, response);
-//            return;
-//        }
+
         if (isRefreshTokenRequest(httpRequest)) {
             chain.doFilter(request, response);
             return;
         }
+        boolean isIgnoreClient = configProperties.getIgnoreClients().contains(WebUtils.getClientId(httpRequest));
         try {
-            checkCode(httpRequest);
+            if (!isIgnoreClient) {
+                checkCode(httpRequest);
+            }
         }catch (ValidateCodeException e){
             handleException(e.getMessage(), httpResponse);
             return;

+ 1 - 1
lxq-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -1 +1 @@
-com.lxq.system.biz.config.BeanConfigScanConfig
+com.lxq.system.biz.config.SysConfigConfiguration

+ 13 - 0
lxq-system/src/main/resources/application-dev.yml

@@ -51,6 +51,19 @@ spring:
           # 以本处为例:第一次间隔 5 秒,第二次间隔 10 秒,以此类推
           multiplier: 2
 
+gateway:
+  aes:
+    enabled: true
+    encode-key: 'CBTU1dD4Kd5pyiGWTsI10jRQ3SvKusSV'
+    encode-iv: 'DYgjCEIMVrj2W9xN'
+    encode-mode: 'CBC'
+    encode-padding: 'PKCS7Padding'
+    filter-url:
+      - /code
+  #不校验验证码的客户端
+  ignore-clients:
+    - admin
+
 file:
   oss:
     bucket-name: laikeba-uni