From 159ec6d9d4b04422b15993c933ebefbc019c8478 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=86=B7=E5=86=B7?= <2270033969@qq.com>
Date: Thu, 18 Apr 2024 18:01:40 +0800
Subject: [PATCH] =?UTF-8?q?:recycle:=20Refactoring=20code.=20=E6=9E=B6?=
=?UTF-8?q?=E6=9E=84=E9=87=8D=E6=9E=84=E6=94=AF=E6=8C=81=20=E4=B8=80?=
=?UTF-8?q?=E5=A5=97=E4=BB=A3=E7=A0=81=E4=B8=A4=E7=A7=8D=E6=96=B9=E5=BC=8F?=
=?UTF-8?q?=E8=BF=90=E8=A1=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pigx-app-server/pigx-app-server-biz/pom.xml | 217 +++++-----
pigx-auth/pom.xml | 69 +++-
.../pigx/auth/PigxAuthApplication.java | 3 +-
.../AuthorizationServerConfiguration.java | 194 +++++----
.../CaptchaCacheServiceProvider.java | 2 +-
.../pigx/auth/endpoint/ImageCodeEndpoint.java | 84 ++++
.../filter/AuthSecurityConfigProperties.java | 30 ++
.../support/filter/PasswordDecoderFilter.java | 139 +++++++
.../support/filter/ValidateCodeFilter.java | 179 +++++++++
...PigxAuthenticationFailureEventHandler.java | 6 -
...m.anji.captcha.service.CaptchaCacheService | 1 +
.../src/main/resources/logback-spring.xml | 6 +
pigx-common/pigx-common-bom/pom.xml | 2 +-
.../core/util/RepeatBodyRequestWrapper.java | 103 +++++
pigx-common/pigx-common-data/pom.xml | 3 +-
.../data/mybatis/DruidSqlLogFilter.java | 3 -
.../openfeign/PigxFeignClientsRegistrar.java | 379 +++++++++---------
.../GlobalExceptionConfiguration.java | 28 +-
.../config/OpenAPIMetadataConfiguration.java | 6 +
.../pigx-flow-engine-biz/pom.xml | 42 +-
.../pigx-flow-task/pigx-flow-task-biz/pom.xml | 42 +-
pigx-gateway/pom.xml | 12 -
.../config/GatewayConfigProperties.java | 25 --
.../config/RouterFunctionConfiguration.java | 59 ---
.../gateway/filter/PasswordDecoderFilter.java | 215 ----------
.../filter/ValidateCodeGatewayFilter.java | 199 ---------
.../handler/ImageCodeCheckHandler.java | 66 ---
.../handler/ImageCodeCreateHandler.java | 63 ---
.../gateway/handler/ImageCodeMathHandler.java | 74 ----
...m.anji.captcha.service.CaptchaCacheService | 1 -
pigx-upms/pigx-upms-biz/pom.xml | 60 +--
.../pigx/admin/PigxAdminApplication.java | 2 -
.../admin/controller/SysTokenController.java | 2 +-
.../src/main/resources/logback-spring.xml | 2 +-
pigx-visual/pigx-codegen/pom.xml | 52 ++-
.../pigx/codegen/PigxCodeGenApplication.java | 2 +-
pigx-visual/pigx-daemon-quartz/pom.xml | 46 ++-
pigx-visual/pigx-mp-platform/pom.xml | 52 ++-
.../pigx/mp/config/WxMpInitConfigRunner.java | 4 +-
pigx-visual/pigx-pay-platform/pom.xml | 59 +--
pom.xml | 46 +--
41 files changed, 1240 insertions(+), 1339 deletions(-)
rename {pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config => pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint}/CaptchaCacheServiceProvider.java (95%)
create mode 100644 pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/ImageCodeEndpoint.java
create mode 100644 pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/AuthSecurityConfigProperties.java
create mode 100755 pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/PasswordDecoderFilter.java
create mode 100644 pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/ValidateCodeFilter.java
create mode 100644 pigx-auth/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService
create mode 100644 pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/RepeatBodyRequestWrapper.java
delete mode 100644 pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/GatewayConfigProperties.java
delete mode 100644 pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/RouterFunctionConfiguration.java
delete mode 100644 pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PasswordDecoderFilter.java
delete mode 100644 pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java
delete mode 100644 pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCheckHandler.java
delete mode 100644 pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCreateHandler.java
delete mode 100755 pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeMathHandler.java
delete mode 100644 pigx-gateway/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService
diff --git a/pigx-app-server/pigx-app-server-biz/pom.xml b/pigx-app-server/pigx-app-server-biz/pom.xml
index 8abf71684..b464ebcd9 100644
--- a/pigx-app-server/pigx-app-server-biz/pom.xml
+++ b/pigx-app-server/pigx-app-server-biz/pom.xml
@@ -1,105 +1,124 @@
- 4.0.0
-
- com.pig4cloud
- pigx-app-server
- 5.4.0
-
+ 4.0.0
+
+ com.pig4cloud
+ pigx-app-server
+ 5.4.0
+
- pigx-app-server-biz
+ pigx-app-server-biz
-
-
-
- org.springframework.boot
- spring-boot-starter-undertow
-
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
-
- com.alibaba.cloud
- spring-cloud-starter-alibaba-nacos-discovery
-
-
-
- com.alibaba.cloud
- spring-cloud-starter-alibaba-nacos-config
-
-
-
- com.pig4cloud
- pigx-common-data
-
-
-
- com.pig4cloud
- pigx-common-security
-
-
-
- com.pig4cloud
- pigx-common-xss
-
-
-
- com.pig4cloud
- pigx-common-sentinel
-
-
-
- com.pig4cloud
- pigx-common-feign
-
-
-
- com.pig4cloud
- pigx-app-server-api
- 5.4.0
-
-
-
- com.pig4cloud
- pigx-common-log
-
-
-
- com.baomidou
- mybatis-plus-spring-boot3-starter
-
-
-
- com.alibaba
- druid-spring-boot-3-starter
-
-
-
- com.mysql
- mysql-connector-j
-
-
-
- com.pig4cloud
- pigx-common-swagger
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- io.fabric8
- docker-maven-plugin
-
-
-
+
+
+
+ org.springframework.boot
+ spring-boot-starter-undertow
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+
+ com.pig4cloud
+ pigx-common-data
+
+
+
+ com.pig4cloud
+ pigx-common-security
+
+
+
+ com.pig4cloud
+ pigx-common-xss
+
+
+
+ com.pig4cloud
+ pigx-common-sentinel
+
+
+
+ com.pig4cloud
+ pigx-common-feign
+
+
+
+ com.pig4cloud
+ pigx-app-server-api
+ 5.4.0
+
+
+
+ com.pig4cloud
+ pigx-common-log
+
+
+
+ com.baomidou
+ mybatis-plus-spring-boot3-starter
+
+
+
+ com.alibaba
+ druid-spring-boot-3-starter
+
+
+
+ com.mysql
+ mysql-connector-j
+
+
+
+ com.pig4cloud
+ pigx-common-swagger
+
+
+
+
+
+ cloud
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ CLASSIC
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ false
+
+
+
+
+
+
diff --git a/pigx-auth/pom.xml b/pigx-auth/pom.xml
index bf126ed52..286a3afca 100644
--- a/pigx-auth/pom.xml
+++ b/pigx-auth/pom.xml
@@ -78,6 +78,23 @@
org.springframework.boot
spring-boot-starter-freemarker
+
+
+ cn.hutool
+ hutool-crypto
+
+
+
+ io.springboot.plugin
+ captcha-core
+ ${captcha.image.version}
+
+
+
+ io.springboot.plugin
+ spring-boot-starter-captcha
+ ${captcha.version}
+
org.springframework.boot
@@ -90,27 +107,35 @@
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
- true
-
-
-
- io.fabric8
- docker-maven-plugin
-
- false
-
-
-
-
+
+
+ cloud
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ CLASSIC
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ false
+
+
+
+
+
+
diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/PigxAuthApplication.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/PigxAuthApplication.java
index eeda3d098..74e5d3f9c 100644
--- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/PigxAuthApplication.java
+++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/PigxAuthApplication.java
@@ -16,7 +16,6 @@
package com.pig4cloud.pigx.auth;
-import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure;
import com.pig4cloud.pigx.common.feign.annotation.EnablePigxFeignClients;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -28,7 +27,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
*/
@EnablePigxFeignClients
@EnableDiscoveryClient
-@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
+@SpringBootApplication
public class PigxAuthApplication {
public static void main(String[] args) {
diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java
index 595450aec..8bfa3522a 100644
--- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java
+++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/config/AuthorizationServerConfiguration.java
@@ -21,6 +21,8 @@ import com.pig4cloud.pigx.auth.support.core.CustomeOAuth2TokenCustomizer;
import com.pig4cloud.pigx.auth.support.core.FormIdentityLoginConfigurer;
import com.pig4cloud.pigx.auth.support.core.PigxDaoAuthenticationProvider;
import com.pig4cloud.pigx.auth.support.core.PigxOAuth2RefreshTokenAuthenticationConverter;
+import com.pig4cloud.pigx.auth.support.filter.PasswordDecoderFilter;
+import com.pig4cloud.pigx.auth.support.filter.ValidateCodeFilter;
import com.pig4cloud.pigx.auth.support.handler.PigxAuthenticationFailureEventHandler;
import com.pig4cloud.pigx.auth.support.handler.PigxAuthenticationSuccessEventHandler;
import com.pig4cloud.pigx.auth.support.password.OAuth2ResourceOwnerPasswordAuthenticationConverter;
@@ -31,6 +33,7 @@ import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.security.handler.FormAuthenticationFailureHandler;
import com.pig4cloud.pigx.common.security.handler.SsoLogoutSuccessHandler;
import lombok.RequiredArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
@@ -44,11 +47,15 @@ import org.springframework.security.oauth2.server.authorization.settings.Authori
import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator;
import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
-import org.springframework.security.oauth2.server.authorization.web.authentication.*;
+import org.springframework.security.oauth2.server.authorization.web.authentication.DelegatingAuthenticationConverter;
+import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter;
+import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeRequestAuthenticationConverter;
+import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2ClientCredentialsAuthenticationConverter;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@@ -57,111 +64,122 @@ import java.util.Arrays;
/**
* @author lengleng
* @date 2022/5/27
- *
+ *
* 认证服务器配置
*/
@Configuration
@RequiredArgsConstructor
public class AuthorizationServerConfiguration {
- private final OAuth2AuthorizationService authorizationService;
+ private final OAuth2AuthorizationService authorizationService;
- @Bean
- @Order(Ordered.HIGHEST_PRECEDENCE)
- public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http,
- PigxAuthenticationSuccessEventHandler successEventHandler,
- PigxAuthenticationFailureEventHandler failureEventHandler) throws Exception {
- OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer();
+ private final PasswordDecoderFilter passwordDecoderFilter;
- http.with(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点
- tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter()) // 注入自定义的授权认证Converter
- .accessTokenResponseHandler(successEventHandler) // 登录成功处理器
- .errorResponseHandler(failureEventHandler);// 登录失败处理器
- }).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证
- oAuth2ClientAuthenticationConfigurer.errorResponseHandler(failureEventHandler))// 处理客户端认证异常
- .authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint// 授权码端点个性化confirm页面
- .consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI)),Customizer.withDefaults());
+ private final ValidateCodeFilter validateCodeFilter;
- AntPathRequestMatcher[] requestMatchers = new AntPathRequestMatcher[] {
- AntPathRequestMatcher.antMatcher("/token/**"), AntPathRequestMatcher.antMatcher("/actuator/**"),
- AntPathRequestMatcher.antMatcher("/css/**"), AntPathRequestMatcher.antMatcher("/error") };
+ @Bean
+ @Order(Ordered.HIGHEST_PRECEDENCE)
+ @ConditionalOnProperty(value = "security.micro", matchIfMissing = true)
+ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http,
+ PigxAuthenticationSuccessEventHandler successEventHandler,
+ PigxAuthenticationFailureEventHandler failureEventHandler) throws Exception {
+ // 增加验证码过滤器
+ http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);
+ // 增加密码解密过滤器
+ http.addFilterBefore(passwordDecoderFilter, UsernamePasswordAuthenticationFilter.class);
- http.authorizeHttpRequests(authorizeRequests -> {
- // 自定义接口、端点暴露
- authorizeRequests.requestMatchers(requestMatchers).permitAll();
- authorizeRequests.anyRequest().authenticated();
- })
- .with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现
- .authorizationServerSettings(
- AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), Customizer.withDefaults());
- http.with(new FormIdentityLoginConfigurer(), Customizer.withDefaults());
- DefaultSecurityFilterChain securityFilterChain = http.build();
+ OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer();
+ http.with(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点
+ tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter()) // 注入自定义的授权认证Converter
+ .accessTokenResponseHandler(successEventHandler) // 登录成功处理器
+ .errorResponseHandler(failureEventHandler);// 登录失败处理器
+ }).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证
+ oAuth2ClientAuthenticationConfigurer.errorResponseHandler(failureEventHandler))// 处理客户端认证异常
+ .authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint// 授权码端点个性化confirm页面
+ .consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI)), Customizer.withDefaults());
- // 注入自定义授权模式实现
- addCustomOAuth2GrantAuthenticationProvider(http);
- return securityFilterChain;
- }
+ AntPathRequestMatcher[] requestMatchers = new AntPathRequestMatcher[]{
+ AntPathRequestMatcher.antMatcher("/token/**"), AntPathRequestMatcher.antMatcher("/actuator/**"),
+ AntPathRequestMatcher.antMatcher("/css/**"), AntPathRequestMatcher.antMatcher("/error")};
- /**
- * 令牌生成规则实现
- * client:username:uuid
- * @return OAuth2TokenGenerator
- */
- @Bean
- public OAuth2TokenGenerator oAuth2TokenGenerator() {
- CustomeOAuth2AccessTokenGenerator accessTokenGenerator = new CustomeOAuth2AccessTokenGenerator();
- // 注入Token 增加关联用户信息
- accessTokenGenerator.setAccessTokenCustomizer(new CustomeOAuth2TokenCustomizer());
- return new DelegatingOAuth2TokenGenerator(accessTokenGenerator, new OAuth2RefreshTokenGenerator());
- }
+ http.authorizeHttpRequests(authorizeRequests -> {
+ // 自定义接口、端点暴露
+ authorizeRequests.requestMatchers(requestMatchers).permitAll();
+ authorizeRequests.anyRequest().authenticated();
+ })
+ .with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现
+ .authorizationServerSettings(
+ AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), Customizer.withDefaults());
+ http.with(new FormIdentityLoginConfigurer(), Customizer.withDefaults());
+ DefaultSecurityFilterChain securityFilterChain = http.build();
- @Bean
- public AuthenticationFailureHandler authenticationFailureHandler() {
- return new FormAuthenticationFailureHandler();
- }
+ // 注入自定义授权模式实现
+ addCustomOAuth2GrantAuthenticationProvider(http);
+ return securityFilterChain;
+ }
- @Bean
- public LogoutSuccessHandler logoutSuccessHandler() {
- return new SsoLogoutSuccessHandler();
- }
+ /**
+ * 令牌生成规则实现
+ * client:username:uuid
+ *
+ * @return OAuth2TokenGenerator
+ */
+ @Bean
+ public OAuth2TokenGenerator oAuth2TokenGenerator() {
+ CustomeOAuth2AccessTokenGenerator accessTokenGenerator = new CustomeOAuth2AccessTokenGenerator();
+ // 注入Token 增加关联用户信息
+ accessTokenGenerator.setAccessTokenCustomizer(new CustomeOAuth2TokenCustomizer());
+ return new DelegatingOAuth2TokenGenerator(accessTokenGenerator, new OAuth2RefreshTokenGenerator());
+ }
- /**
- * request -> xToken 注入请求转换器
- * @return DelegatingAuthenticationConverter
- */
- private AuthenticationConverter accessTokenRequestConverter() {
- return new DelegatingAuthenticationConverter(Arrays.asList(
- new OAuth2ResourceOwnerPasswordAuthenticationConverter(),
- new OAuth2ResourceOwnerSmsAuthenticationConverter(), new PigxOAuth2RefreshTokenAuthenticationConverter(),
- new OAuth2ClientCredentialsAuthenticationConverter(),
- new OAuth2AuthorizationCodeAuthenticationConverter(),
- new OAuth2AuthorizationCodeRequestAuthenticationConverter()));
- }
+ @Bean
+ public AuthenticationFailureHandler authenticationFailureHandler() {
+ return new FormAuthenticationFailureHandler();
+ }
- /**
- * 注入授权模式实现提供方
- *
- * 1. 密码模式
- * 2. 短信登录
- *
- */
- @SuppressWarnings("unchecked")
- private void addCustomOAuth2GrantAuthenticationProvider(HttpSecurity http) {
- AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
- OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class);
+ @Bean
+ public LogoutSuccessHandler logoutSuccessHandler() {
+ return new SsoLogoutSuccessHandler();
+ }
- OAuth2ResourceOwnerPasswordAuthenticationProvider resourceOwnerPasswordAuthenticationProvider = new OAuth2ResourceOwnerPasswordAuthenticationProvider(
- authenticationManager, authorizationService, oAuth2TokenGenerator());
+ /**
+ * request -> xToken 注入请求转换器
+ *
+ * @return DelegatingAuthenticationConverter
+ */
+ @Bean
+ public AuthenticationConverter accessTokenRequestConverter() {
+ return new DelegatingAuthenticationConverter(Arrays.asList(
+ new OAuth2ResourceOwnerPasswordAuthenticationConverter(),
+ new OAuth2ResourceOwnerSmsAuthenticationConverter(), new PigxOAuth2RefreshTokenAuthenticationConverter(),
+ new OAuth2ClientCredentialsAuthenticationConverter(),
+ new OAuth2AuthorizationCodeAuthenticationConverter(),
+ new OAuth2AuthorizationCodeRequestAuthenticationConverter()));
+ }
- OAuth2ResourceOwnerSmsAuthenticationProvider resourceOwnerSmsAuthenticationProvider = new OAuth2ResourceOwnerSmsAuthenticationProvider(
- authenticationManager, authorizationService, oAuth2TokenGenerator());
+ /**
+ * 注入授权模式实现提供方
+ *
+ * 1. 密码模式
+ * 2. 短信登录
+ */
+ @SuppressWarnings("unchecked")
+ private void addCustomOAuth2GrantAuthenticationProvider(HttpSecurity http) {
+ AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
+ OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class);
- // 处理 UsernamePasswordAuthenticationToken
- http.authenticationProvider(new PigxDaoAuthenticationProvider());
- // 处理 OAuth2ResourceOwnerPasswordAuthenticationToken
- http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider);
- // 处理 OAuth2ResourceOwnerSmsAuthenticationToken
- http.authenticationProvider(resourceOwnerSmsAuthenticationProvider);
- }
+ OAuth2ResourceOwnerPasswordAuthenticationProvider resourceOwnerPasswordAuthenticationProvider = new OAuth2ResourceOwnerPasswordAuthenticationProvider(
+ authenticationManager, authorizationService, oAuth2TokenGenerator());
+
+ OAuth2ResourceOwnerSmsAuthenticationProvider resourceOwnerSmsAuthenticationProvider = new OAuth2ResourceOwnerSmsAuthenticationProvider(
+ authenticationManager, authorizationService, oAuth2TokenGenerator());
+
+ // 处理 UsernamePasswordAuthenticationToken
+ http.authenticationProvider(new PigxDaoAuthenticationProvider());
+ // 处理 OAuth2ResourceOwnerPasswordAuthenticationToken
+ http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider);
+ // 处理 OAuth2ResourceOwnerSmsAuthenticationToken
+ http.authenticationProvider(resourceOwnerSmsAuthenticationProvider);
+ }
}
diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/CaptchaCacheServiceProvider.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/CaptchaCacheServiceProvider.java
similarity index 95%
rename from pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/CaptchaCacheServiceProvider.java
rename to pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/CaptchaCacheServiceProvider.java
index 1b582905a..371b78c93 100644
--- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/CaptchaCacheServiceProvider.java
+++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/CaptchaCacheServiceProvider.java
@@ -1,4 +1,4 @@
-package com.pig4cloud.pigx.gateway.config;
+package com.pig4cloud.pigx.auth.endpoint;
import com.anji.captcha.service.CaptchaCacheService;
import org.springframework.beans.factory.annotation.Autowired;
diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/ImageCodeEndpoint.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/ImageCodeEndpoint.java
new file mode 100644
index 000000000..b8920c1f8
--- /dev/null
+++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/ImageCodeEndpoint.java
@@ -0,0 +1,84 @@
+package com.pig4cloud.pigx.auth.endpoint;
+
+import com.anji.captcha.model.vo.CaptchaVO;
+import com.anji.captcha.service.CaptchaService;
+import com.pig4cloud.pigx.common.core.constant.CacheConstants;
+import com.pig4cloud.pigx.common.core.constant.CommonConstants;
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
+import com.pig4cloud.pigx.common.core.util.R;
+import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
+import io.springboot.captcha.ArithmeticCaptcha;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 验证码相关的接口
+ *
+ * @author lengleng
+ * @date 2022/6/27
+ */
+@RestController
+@RequestMapping("/code")
+@RequiredArgsConstructor
+public class ImageCodeEndpoint {
+
+ private static final Integer DEFAULT_IMAGE_WIDTH = 100;
+
+ private static final Integer DEFAULT_IMAGE_HEIGHT = 40;
+
+ private final StringRedisTemplate redisTemplate;
+
+ /**
+ * 创建图形验证码
+ */
+ @SneakyThrows
+ @GetMapping("/image")
+ public void image(String randomStr, HttpServletResponse response) {
+ ArithmeticCaptcha captcha = new ArithmeticCaptcha(DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT);
+
+ String result = captcha.text();
+ redisTemplate.opsForValue()
+ .set(CacheConstants.DEFAULT_CODE_KEY + randomStr, result, SecurityConstants.CODE_TIME, TimeUnit.SECONDS);
+ // 转换流信息写出
+ captcha.out(response.getOutputStream());
+ }
+
+ /**
+ * 行为
+ * 创建滑块图形验证码
+ */
+ @SneakyThrows
+ @GetMapping("/create")
+ public R behavior() {
+ CaptchaVO vo = new CaptchaVO();
+ vo.setCaptchaType(CommonConstants.IMAGE_CODE_TYPE);
+ CaptchaService captchaService = SpringContextHolder.getBean(CaptchaService.class);
+ return R.ok(captchaService.get(vo));
+ }
+
+ /**
+ * 行为
+ * 创建滑块图形验证码
+ */
+ @SneakyThrows
+ @PostMapping("/check")
+ public R check(HttpServletRequest request) {
+ CaptchaVO vo = new CaptchaVO();
+ vo.setPointJson(request.getParameter("pointJson"));
+ vo.setToken(request.getParameter("token"));
+ vo.setCaptchaType(CommonConstants.IMAGE_CODE_TYPE);
+
+ CaptchaService captchaService = SpringContextHolder.getBean(CaptchaService.class);
+ return R.ok(captchaService.check(vo));
+ }
+
+}
diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/AuthSecurityConfigProperties.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/AuthSecurityConfigProperties.java
new file mode 100644
index 000000000..4c4b547c4
--- /dev/null
+++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/AuthSecurityConfigProperties.java
@@ -0,0 +1,30 @@
+package com.pig4cloud.pigx.auth.support.filter;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author lengleng
+ * @date 2020/10/4
+ *
+ * 网关配置文件
+ */
+@Data
+@Component
+@RefreshScope
+@ConfigurationProperties("security")
+public class AuthSecurityConfigProperties {
+
+ /**
+ * 是否是微服务架构
+ */
+ private boolean isMicro;
+
+ /**
+ * 网关解密登录前端密码 秘钥
+ */
+ private String encodeKey;
+
+}
diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/PasswordDecoderFilter.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/PasswordDecoderFilter.java
new file mode 100755
index 000000000..ef3fbf8d3
--- /dev/null
+++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/PasswordDecoderFilter.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.pig4cloud.pigx.auth.support.filter;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.Mode;
+import cn.hutool.crypto.Padding;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.symmetric.AES;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.pig4cloud.pigx.common.core.constant.CacheConstants;
+import com.pig4cloud.pigx.common.core.constant.CommonConstants;
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
+import com.pig4cloud.pigx.common.core.constant.enums.EncFlagTypeEnum;
+import com.pig4cloud.pigx.common.core.util.RepeatBodyRequestWrapper;
+import com.pig4cloud.pigx.common.core.util.WebUtils;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * @author lengleng
+ * @date 2019 /2/1 密码解密工具类
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class PasswordDecoderFilter extends OncePerRequestFilter {
+
+ private final AuthSecurityConfigProperties authSecurityConfigProperties;
+
+ private final StringRedisTemplate redisTemplate;
+
+ private static final String PASSWORD = "password";
+
+ private static final String KEY_ALGORITHM = "AES";
+
+ static {
+ // 关闭hutool 强制关闭Bouncy Castle库的依赖
+ SecureUtil.disableBouncyCastle();
+ }
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
+ throws ServletException, IOException {
+ // 不是登录请求,直接向下执行
+ if (!StrUtil.containsAnyIgnoreCase(request.getRequestURI(), SecurityConstants.OAUTH_TOKEN_URL)) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+ // 2. 刷新token类型,直接向下执行
+ String grantType = request.getParameter("grant_type");
+ if (StrUtil.equals(SecurityConstants.REFRESH_TOKEN, grantType)) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+ // 3. 判断客户端是否需要解密,明文传输直接向下执行
+ if (!isEncClient(request)) {
+ chain.doFilter(request, response);
+ return; }
+
+ // 将请求流转换为可多次读取的请求流
+ RepeatBodyRequestWrapper requestWrapper = new RepeatBodyRequestWrapper(request);
+ Map parameterMap = requestWrapper.getParameterMap();
+
+ // 构建前端对应解密AES 因子
+ AES aes = new AES(Mode.CFB, Padding.NoPadding,
+ new SecretKeySpec(authSecurityConfigProperties.getEncodeKey().getBytes(), KEY_ALGORITHM),
+ new IvParameterSpec(authSecurityConfigProperties.getEncodeKey().getBytes()));
+
+ parameterMap.forEach((k, v) -> {
+ String[] values = parameterMap.get(k);
+ if (!PASSWORD.equals(k) || ArrayUtil.isEmpty(values)) {
+ return;
+ }
+
+ // 解密密码
+ String decryptPassword = aes.decryptStr(values[0]);
+ parameterMap.put(k, new String[]{decryptPassword});
+ });
+ chain.doFilter(requestWrapper, response);
+ }
+
+ /**
+ * 根据请求的clientId 查询客户端配置是否是加密传输
+ *
+ * @param request 请求上下文
+ * @return true 加密传输 、 false 原文传输
+ */
+ private boolean isEncClient(HttpServletRequest request) {
+ String header = request.getHeader(HttpHeaders.AUTHORIZATION);
+ String clientId = WebUtils.extractClientId(header).orElse(null);
+ // 获取租户拼接区分租户的key
+ String tenantId = request.getHeader(CommonConstants.TENANT_ID);
+ String key = String.format("%s:%s:%s", StrUtil.isBlank(tenantId) ? CommonConstants.TENANT_ID_1 : tenantId,
+ CacheConstants.CLIENT_FLAG, clientId);
+
+ String val = redisTemplate.opsForValue().get(key);
+
+ // 当配置不存在时,默认需要解密
+ if (val == null) {
+ return true;
+ }
+
+ JSONObject information = JSONUtil.parseObj(val);
+ return !StrUtil.equals(EncFlagTypeEnum.NO.getType(), information.getStr(CommonConstants.ENC_FLAG));
+ }
+
+}
diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/ValidateCodeFilter.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/ValidateCodeFilter.java
new file mode 100644
index 000000000..5995ddaf5
--- /dev/null
+++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/filter/ValidateCodeFilter.java
@@ -0,0 +1,179 @@
+package com.pig4cloud.pigx.auth.support.filter;
+
+/**
+ * 登录前处理器
+ *
+ * @author lengleng
+ * @date 2024/4/3
+ */
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.anji.captcha.model.vo.CaptchaVO;
+import com.anji.captcha.service.CaptchaService;
+import com.pig4cloud.pigx.common.core.constant.CacheConstants;
+import com.pig4cloud.pigx.common.core.constant.CommonConstants;
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
+import com.pig4cloud.pigx.common.core.constant.enums.CaptchaFlagTypeEnum;
+import com.pig4cloud.pigx.common.core.exception.ValidateCodeException;
+import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
+import com.pig4cloud.pigx.common.core.util.WebUtils;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
+import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+/**
+ * @author lbw
+ * @date 2024-01-06
+ *
+ * 登录前置处理器: 前端密码传输密文解密,验证码处理
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class ValidateCodeFilter extends OncePerRequestFilter {
+
+
+ private final StringRedisTemplate redisTemplate;
+
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+ throws ServletException, IOException {
+
+ String requestUrl = request.getServletPath();
+
+ // 不是登录URL 请求直接跳过
+ if (!SecurityConstants.OAUTH_TOKEN_URL.equals(requestUrl)) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // 如果登录URL 但是刷新token的请求,直接向下执行
+ String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
+ if (StrUtil.containsAny(grantType, SecurityConstants.REFRESH_TOKEN)) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // mobile模式, 如果请求不包含mobile 参数直接
+ String mobile = request.getParameter(SecurityConstants.GRANT_MOBILE);
+ if (StrUtil.equals(SecurityConstants.GRANT_MOBILE, grantType) && StrUtil.isBlank(mobile)) {
+ throw new OAuth2AuthenticationException(SecurityConstants.GRANT_MOBILE);
+ }
+
+ // mobile模式, 社交登录模式不校验验证码直接跳过
+ if (StrUtil.equals(SecurityConstants.GRANT_MOBILE, grantType) && !StrUtil.contains(mobile, "SMS")) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // 判断客户端是否跳过检验
+ if (!isCheckCaptchaClient(request)) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ // 校验验证码 1. 客户端开启验证码 2. 短信模式
+ try {
+ checkCode();
+ filterChain.doFilter(request, response);
+ } catch (ValidateCodeException validateCodeException) {
+ throw new OAuth2AuthenticationException(validateCodeException.getMessage());
+ }
+ }
+
+ /**
+ * 校验验证码
+ */
+ private void checkCode() throws ValidateCodeException {
+ HttpServletRequest request = WebUtils.getRequest();
+ String code = request.getParameter("code");
+
+ if (StrUtil.isBlank(code)) {
+ throw new ValidateCodeException("验证码不能为空");
+ }
+
+ String randomStr = request.getParameter("randomStr");
+
+ // https://gitee.com/log4j/pig/issues/IWA0D
+ String mobile = request.getParameter("mobile");
+ if (StrUtil.isNotBlank(mobile)) {
+ randomStr = mobile;
+ }
+
+ // 若是滑块登录
+ if (CommonConstants.IMAGE_CODE_TYPE.equalsIgnoreCase(randomStr)) {
+ CaptchaService captchaService = SpringContextHolder.getBean(CaptchaService.class);
+ CaptchaVO vo = new CaptchaVO();
+ vo.setCaptchaVerification(code);
+ vo.setCaptchaType(CommonConstants.IMAGE_CODE_TYPE);
+ if (!captchaService.verification(vo).isSuccess()) {
+ throw new ValidateCodeException("验证码不能为空");
+ }
+ return;
+ }
+
+
+ String key = CacheConstants.DEFAULT_CODE_KEY + randomStr;
+ if (Boolean.FALSE.equals(redisTemplate.hasKey(key))) {
+ throw new ValidateCodeException("验证码不合法");
+ }
+
+ Object codeObj = redisTemplate.opsForValue().get(key);
+
+ if (codeObj == null) {
+ throw new ValidateCodeException("验证码不合法");
+ }
+
+ String saveCode = codeObj.toString();
+ if (StrUtil.isBlank(saveCode)) {
+ redisTemplate.delete(key);
+ throw new ValidateCodeException("验证码不合法");
+ }
+
+ if (!StrUtil.equals(saveCode, code)) {
+ redisTemplate.delete(key);
+ throw new ValidateCodeException("验证码不合法");
+ }
+
+ redisTemplate.delete(key);
+ }
+
+ /**
+ * 是否需要校验客户端,根据client 查询客户端配置
+ *
+ * @param request 请求
+ * @return true 需要校验, false 不需要校验
+ */
+ private boolean isCheckCaptchaClient(HttpServletRequest request) {
+ String header = request.getHeader(HttpHeaders.AUTHORIZATION);
+ String clientId = WebUtils.extractClientId(header).orElse(null);
+ // 获取租户拼接区分租户的key
+ String tenantId = request.getHeader(CommonConstants.TENANT_ID);
+ String key = String.format("%s:%s:%s", StrUtil.isBlank(tenantId) ? CommonConstants.TENANT_ID_1 : tenantId,
+ CacheConstants.CLIENT_FLAG, clientId);
+
+ String val = redisTemplate.opsForValue().get(key);
+
+ // 当配置不存在时,不用校验
+ if (val == null) {
+ return false;
+ }
+
+ JSONObject information = JSONUtil.parseObj(val);
+ return !StrUtil.equals(CaptchaFlagTypeEnum.OFF.getType(), information.getStr(CommonConstants.CAPTCHA_FLAG));
+ }
+}
diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/handler/PigxAuthenticationFailureEventHandler.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/handler/PigxAuthenticationFailureEventHandler.java
index 09700a2be..b8e831fcd 100644
--- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/handler/PigxAuthenticationFailureEventHandler.java
+++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/support/handler/PigxAuthenticationFailureEventHandler.java
@@ -23,7 +23,6 @@ import com.pig4cloud.pigx.common.core.constant.CacheConstants;
import com.pig4cloud.pigx.common.core.constant.CommonConstants;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.KeyStrResolver;
-import com.pig4cloud.pigx.common.core.util.MsgUtils;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.core.util.WebUtils;
import com.pig4cloud.pigx.common.data.resolver.ParamResolver;
@@ -163,11 +162,6 @@ public class PigxAuthenticationFailureEventHandler implements AuthenticationFail
errorMessage = exception.getLocalizedMessage();
}
- // 手机号登录
- String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
- if (SecurityConstants.APP.equals(grantType)) {
- errorMessage = MsgUtils.getSecurityMessage("AbstractUserDetailsAuthenticationProvider.smsBadCredentials");
- }
this.errorHttpResponseConverter.write(R.failed(errorMessage), MediaType.APPLICATION_JSON, httpResponse);
}
diff --git a/pigx-auth/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService b/pigx-auth/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService
new file mode 100644
index 000000000..39e4ea0c5
--- /dev/null
+++ b/pigx-auth/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService
@@ -0,0 +1 @@
+com.pig4cloud.pigx.auth.endpoint.CaptchaCacheServiceProvider
diff --git a/pigx-auth/src/main/resources/logback-spring.xml b/pigx-auth/src/main/resources/logback-spring.xml
index ef137181c..13d4db2e5 100644
--- a/pigx-auth/src/main/resources/logback-spring.xml
+++ b/pigx-auth/src/main/resources/logback-spring.xml
@@ -79,6 +79,12 @@
+
+
+
+
+
+
diff --git a/pigx-common/pigx-common-bom/pom.xml b/pigx-common/pigx-common-bom/pom.xml
index 657e3ba9d..317257eea 100644
--- a/pigx-common/pigx-common-bom/pom.xml
+++ b/pigx-common/pigx-common-bom/pom.xml
@@ -28,7 +28,7 @@
8.4.1.jre8
8.1.2.192
6.2.0
- 3.0.3
+ 3.0.5
2.1.0
2.2.14
4.6.0
diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/RepeatBodyRequestWrapper.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/RepeatBodyRequestWrapper.java
new file mode 100644
index 000000000..574b0a628
--- /dev/null
+++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/RepeatBodyRequestWrapper.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2023-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.pig4cloud.pigx.common.core.util;
+
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StreamUtils;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Map;
+
+/**
+ * Request包装类:允许 body 重复读取
+ *
+ * @author Hccake
+ */
+@Slf4j
+public class RepeatBodyRequestWrapper extends HttpServletRequestWrapper {
+
+ private final byte[] bodyByteArray;
+
+ private final Map parameterMap;
+
+ public RepeatBodyRequestWrapper(HttpServletRequest request) {
+ super(request);
+ this.bodyByteArray = getByteBody(request);
+ this.parameterMap = super.getParameterMap();
+ }
+
+ @Override
+ public BufferedReader getReader() {
+ return ObjectUtils.isEmpty(this.bodyByteArray) ? null
+ : new BufferedReader(new InputStreamReader(getInputStream()));
+ }
+
+ @Override
+ public ServletInputStream getInputStream() {
+ final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.bodyByteArray);
+ return new ServletInputStream() {
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public boolean isReady() {
+ return false;
+ }
+
+ @Override
+ public void setReadListener(ReadListener readListener) {
+ // doNoting
+ }
+
+ @Override
+ public int read() {
+ return byteArrayInputStream.read();
+ }
+ };
+ }
+
+ private static byte[] getByteBody(HttpServletRequest request) {
+ byte[] body = new byte[0];
+ try {
+ body = StreamUtils.copyToByteArray(request.getInputStream());
+ }
+ catch (IOException e) {
+ log.error("解析流中数据异常", e);
+ }
+ return body;
+ }
+
+ /**
+ * 重写 getParameterMap() 方法 解决 undertow 中流被读取后,会进行标记,从而导致无法正确获取 body 中的表单数据的问题
+ * @return Map parameterMap
+ */
+ @Override
+ public Map getParameterMap() {
+ return this.parameterMap;
+ }
+
+}
diff --git a/pigx-common/pigx-common-data/pom.xml b/pigx-common/pigx-common-data/pom.xml
index 0b3d0fb63..fbd3c3b87 100644
--- a/pigx-common/pigx-common-data/pom.xml
+++ b/pigx-common/pigx-common-data/pom.xml
@@ -52,7 +52,8 @@
com.alibaba
- druid-spring-boot-3-starter
+ druid
+ true
diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/DruidSqlLogFilter.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/DruidSqlLogFilter.java
index 1dd957acb..08c14a12f 100644
--- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/DruidSqlLogFilter.java
+++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/mybatis/DruidSqlLogFilter.java
@@ -25,7 +25,6 @@ import com.alibaba.druid.filter.FilterEventAdapter;
import com.alibaba.druid.proxy.jdbc.JdbcParameter;
import com.alibaba.druid.proxy.jdbc.ResultSetProxy;
import com.alibaba.druid.proxy.jdbc.StatementProxy;
-import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor;
@@ -34,7 +33,6 @@ import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.util.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.annotation.Import;
import java.sql.SQLException;
import java.time.temporal.TemporalAccessor;
@@ -53,7 +51,6 @@ import java.util.Map;
*/
@Slf4j
@RequiredArgsConstructor
-@Import(DruidDataSourceAutoConfigure.class)
public class DruidSqlLogFilter extends FilterEventAdapter {
private static final SQLUtils.FormatOption FORMAT_OPTION = new SQLUtils.FormatOption(false, false);
diff --git a/pigx-common/pigx-common-feign/src/main/java/org/springframework/cloud/openfeign/PigxFeignClientsRegistrar.java b/pigx-common/pigx-common-feign/src/main/java/org/springframework/cloud/openfeign/PigxFeignClientsRegistrar.java
index 3eb609111..b5d782e20 100644
--- a/pigx-common/pigx-common-feign/src/main/java/org/springframework/cloud/openfeign/PigxFeignClientsRegistrar.java
+++ b/pigx-common/pigx-common-feign/src/main/java/org/springframework/cloud/openfeign/PigxFeignClientsRegistrar.java
@@ -17,7 +17,6 @@
package org.springframework.cloud.openfeign;
-import com.pig4cloud.pigx.common.feign.PigxFeignAutoConfiguration;
import lombok.Getter;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
@@ -31,7 +30,6 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
-import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
@@ -48,226 +46,229 @@ import java.util.Map;
* feign 自动配置功能 from mica
*/
public class PigxFeignClientsRegistrar
- implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware, EnvironmentAware {
+ implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware, EnvironmentAware {
- private final static String BASE_URL = "http://127.0.0.1:${server.port}${server.servlet.context-path}";
+ private final static String BASE_URL = "http://127.0.0.1:${server.port}${server.servlet.context-path}";
- @Getter
- private ClassLoader beanClassLoader;
+ @Getter
+ private ClassLoader beanClassLoader;
- @Getter
- private Environment environment;
+ @Getter
+ private Environment environment;
- @Override
- public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
- registerFeignClients(registry);
- }
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
+ registerFeignClients(registry);
+ }
- @Override
- public void setBeanClassLoader(ClassLoader classLoader) {
- this.beanClassLoader = classLoader;
- }
+ @Override
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
- private void registerFeignClients(BeanDefinitionRegistry registry) {
- List feignClients = new ArrayList<>();
+ private void registerFeignClients(BeanDefinitionRegistry registry) {
+ List feignClients = new ArrayList<>();
- // 支持 springboot 2.7 + 最新版本的配置方式
- ImportCandidates.load(FeignClient.class, getBeanClassLoader()).forEach(feignClients::add);
+ // 支持 springboot 2.7 + 最新版本的配置方式
+ ImportCandidates.load(FeignClient.class, getBeanClassLoader()).forEach(feignClients::add);
- // 如果 spring.factories 里为空
- if (feignClients.isEmpty()) {
- return;
- }
- for (String className : feignClients) {
- try {
- Class> clazz = beanClassLoader.loadClass(className);
- AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(clazz,
- FeignClient.class);
- if (attributes == null) {
- continue;
- }
- // 如果已经存在该 bean,支持原生的 Feign
- if (registry.containsBeanDefinition(className)) {
- continue;
- }
+ // 如果 spring.factories 里为空
+ if (feignClients.isEmpty()) {
+ return;
+ }
+ for (String className : feignClients) {
+ try {
+ Class> clazz = beanClassLoader.loadClass(className);
+ AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(clazz,
+ FeignClient.class);
+ if (attributes == null) {
+ continue;
+ }
- registerClientConfiguration(registry, getClientName(attributes), className,
- attributes.get("configuration"));
+ // 如果是单体项目自动注入 & url 为空
+ Boolean isMicro = environment.getProperty("spring.cloud.nacos.discovery.enabled", Boolean.class, true);
+ // 如果已经存在该 bean,支持原生的 Feign
+ if (registry.containsBeanDefinition(className) && isMicro) {
+ continue;
+ }
- validate(attributes);
- BeanDefinitionBuilder definition = BeanDefinitionBuilder
- .genericBeanDefinition(FeignClientFactoryBean.class);
- definition.addPropertyValue("url", getUrl(attributes));
- definition.addPropertyValue("path", getPath(attributes));
- String name = getName(attributes);
- definition.addPropertyValue("name", name);
+ registerClientConfiguration(registry, getClientName(attributes), className,
+ attributes.get("configuration"));
- // 兼容最新版本的 spring-cloud-openfeign,尚未发布
- StringBuilder aliasBuilder = new StringBuilder(18);
- if (attributes.containsKey("contextId")) {
- String contextId = getContextId(attributes);
- aliasBuilder.append(contextId);
- definition.addPropertyValue("contextId", contextId);
- }
- else {
- aliasBuilder.append(name);
- }
+ validate(attributes);
+ BeanDefinitionBuilder definition = BeanDefinitionBuilder
+ .genericBeanDefinition(FeignClientFactoryBean.class);
+ definition.addPropertyValue("url", getUrl(attributes));
+ definition.addPropertyValue("path", getPath(attributes));
+ String name = getName(attributes);
+ definition.addPropertyValue("name", name);
- definition.addPropertyValue("type", className);
- definition.addPropertyValue("dismiss404",
- Boolean.parseBoolean(String.valueOf(attributes.get("dismiss404"))));
- Object fallbackFactory = attributes.get("fallbackFactory");
- if (fallbackFactory != null) {
- definition.addPropertyValue("fallbackFactory", fallbackFactory instanceof Class ? fallbackFactory
- : ClassUtils.resolveClassName(fallbackFactory.toString(), null));
- }
- definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
- definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
+ // 兼容最新版本的 spring-cloud-openfeign,尚未发布
+ StringBuilder aliasBuilder = new StringBuilder(18);
+ if (attributes.containsKey("contextId")) {
+ String contextId = getContextId(attributes);
+ aliasBuilder.append(contextId);
+ definition.addPropertyValue("contextId", contextId);
+ } else {
+ aliasBuilder.append(name);
+ }
- AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
+ definition.addPropertyValue("type", className);
+ definition.addPropertyValue("dismiss404",
+ Boolean.parseBoolean(String.valueOf(attributes.get("dismiss404"))));
+ Object fallbackFactory = attributes.get("fallbackFactory");
+ if (fallbackFactory != null) {
+ definition.addPropertyValue("fallbackFactory", fallbackFactory instanceof Class ? fallbackFactory
+ : ClassUtils.resolveClassName(fallbackFactory.toString(), null));
+ }
+ definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
+ definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
- // alias
- String alias = aliasBuilder.append("FeignClient").toString();
+ AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
- // has a default, won't be null
- boolean primary = (Boolean) attributes.get("primary");
+ // alias
+ String alias = aliasBuilder.append("FeignClient").toString();
- beanDefinition.setPrimary(primary);
+ // has a default, won't be null
+ boolean primary = (Boolean) attributes.get("primary");
- String qualifier = getQualifier(attributes);
- if (StringUtils.hasText(qualifier)) {
- alias = qualifier;
- }
+ beanDefinition.setPrimary(primary);
- BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
- new String[] { alias });
- BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
+ String qualifier = getQualifier(attributes);
+ if (StringUtils.hasText(qualifier)) {
+ alias = qualifier;
+ }
- }
- catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
- }
+ BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
+ new String[]{alias});
+ BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
- /**
- * Return the class used by {@link SpringFactoriesLoader} to load configuration
- * candidates.
- * @return the factory class
- */
- private Class> getSpringFactoriesLoaderFactoryClass() {
- return PigxFeignAutoConfiguration.class;
- }
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ }
- private void validate(Map attributes) {
- AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
- // This blows up if an aliased property is overspecified
- FeignClientsRegistrar.validateFallback(annotation.getClass("fallback"));
- FeignClientsRegistrar.validateFallbackFactory(annotation.getClass("fallbackFactory"));
- }
- private String getName(Map attributes) {
- String name = (String) attributes.get("serviceId");
- if (!StringUtils.hasText(name)) {
- name = (String) attributes.get("name");
- }
- if (!StringUtils.hasText(name)) {
- name = (String) attributes.get("value");
- }
- name = resolve(name);
- return FeignClientsRegistrar.getName(name);
- }
+ private void validate(Map attributes) {
+ AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
+ // This blows up if an aliased property is overspecified
+ FeignClientsRegistrar.validateFallback(annotation.getClass("fallback"));
+ FeignClientsRegistrar.validateFallbackFactory(annotation.getClass("fallbackFactory"));
+ }
- private String getContextId(Map attributes) {
- String contextId = (String) attributes.get("contextId");
- if (!StringUtils.hasText(contextId)) {
- return getName(attributes);
- }
+ private String getName(Map attributes) {
+ String name = (String) attributes.get("serviceId");
+ if (!StringUtils.hasText(name)) {
+ name = (String) attributes.get("name");
+ }
+ if (!StringUtils.hasText(name)) {
+ name = (String) attributes.get("value");
+ }
+ name = resolve(name);
+ return FeignClientsRegistrar.getName(name);
+ }
- contextId = resolve(contextId);
- return FeignClientsRegistrar.getName(contextId);
- }
+ private String getContextId(Map attributes) {
+ String contextId = (String) attributes.get("contextId");
+ if (!StringUtils.hasText(contextId)) {
+ return getName(attributes);
+ }
- private String resolve(String value) {
- if (StringUtils.hasText(value)) {
- return this.environment.resolvePlaceholders(value);
- }
- return value;
- }
+ contextId = resolve(contextId);
+ return FeignClientsRegistrar.getName(contextId);
+ }
- private String getUrl(Map attributes) {
- // 如果是单体项目自动注入 & url 为空
- String url = (String) attributes.get("url");
- boolean present = ClassUtils.isPresent("com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient",
- this.getClass().getClassLoader());
- if (!StringUtils.hasText(url) && !present) {
- url = resolve(BASE_URL);
- }
+ private String resolve(String value) {
+ if (StringUtils.hasText(value)) {
+ return this.environment.resolvePlaceholders(value);
+ }
+ return value;
+ }
- return FeignClientsRegistrar.getUrl(url);
- }
- private String getPath(Map attributes) {
- String path = resolve((String) attributes.get("path"));
- return FeignClientsRegistrar.getPath(path);
- }
+ private String getUrl(Map attributes) {
- @Nullable
- private String getQualifier(@Nullable Map client) {
- if (client == null) {
- return null;
- }
- String qualifier = (String) client.get("qualifier");
- if (StringUtils.hasText(qualifier)) {
- return qualifier;
- }
- return null;
- }
+ // 如果是单体项目自动注入 & url 为空
+ Boolean isMicro = environment.getProperty("spring.cloud.nacos.discovery.enabled", Boolean.class, true);
- @Nullable
- private String getClientName(@Nullable Map client) {
- if (client == null) {
- return null;
- }
- String value = (String) client.get("contextId");
- if (!StringUtils.hasText(value)) {
- value = (String) client.get("value");
- }
- if (!StringUtils.hasText(value)) {
- value = (String) client.get("name");
- }
- if (!StringUtils.hasText(value)) {
- value = (String) client.get("serviceId");
- }
- if (StringUtils.hasText(value)) {
- return value;
- }
+ if (isMicro) {
+ return null;
+ }
- throw new IllegalStateException(
- "Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());
- }
+ Object objUrl = attributes.get("url");
- private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
- builder.addConstructorArgValue(name);
- builder.addConstructorArgValue(configuration);
- registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
- builder.getBeanDefinition());
- }
+ String url = "";
+ if (StringUtils.hasText(objUrl.toString())) {
+ url = resolve(objUrl.toString());
+ } else {
+ url = resolve(BASE_URL);
+ }
- private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object className,
- Object configuration) {
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
- builder.addConstructorArgValue(name);
- builder.addConstructorArgValue(className);
- builder.addConstructorArgValue(configuration);
- registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
- builder.getBeanDefinition());
- }
+ return FeignClientsRegistrar.getUrl(url);
+ }
- @Override
- public void setEnvironment(Environment environment) {
- this.environment = environment;
- }
+ private String getPath(Map attributes) {
+ String path = resolve((String) attributes.get("path"));
+ return FeignClientsRegistrar.getPath(path);
+ }
+
+ @Nullable
+ private String getQualifier(@Nullable Map client) {
+ if (client == null) {
+ return null;
+ }
+ String qualifier = (String) client.get("qualifier");
+ if (StringUtils.hasText(qualifier)) {
+ return qualifier;
+ }
+ return null;
+ }
+
+ @Nullable
+ private String getClientName(@Nullable Map client) {
+ if (client == null) {
+ return null;
+ }
+ String value = (String) client.get("contextId");
+ if (!StringUtils.hasText(value)) {
+ value = (String) client.get("value");
+ }
+ if (!StringUtils.hasText(value)) {
+ value = (String) client.get("name");
+ }
+ if (!StringUtils.hasText(value)) {
+ value = (String) client.get("serviceId");
+ }
+ if (StringUtils.hasText(value)) {
+ return value;
+ }
+
+ throw new IllegalStateException(
+ "Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());
+ }
+
+ private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
+ builder.addConstructorArgValue(name);
+ builder.addConstructorArgValue(configuration);
+ registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
+ builder.getBeanDefinition());
+ }
+
+ private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object className,
+ Object configuration) {
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
+ builder.addConstructorArgValue(name);
+ builder.addConstructorArgValue(className);
+ builder.addConstructorArgValue(configuration);
+ registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
+ builder.getBeanDefinition());
+ }
+
+ @Override
+ public void setEnvironment(Environment environment) {
+ this.environment = environment;
+ }
}
diff --git a/pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/GlobalExceptionConfiguration.java b/pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/GlobalExceptionConfiguration.java
index 773d23c43..93b6726ee 100644
--- a/pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/GlobalExceptionConfiguration.java
+++ b/pigx-common/pigx-common-gateway/src/main/java/com/pig4cloud/pigx/common/gateway/configuration/GlobalExceptionConfiguration.java
@@ -5,20 +5,16 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.pig4cloud.pigx.common.core.util.R;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory;
-import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
-import org.springframework.web.reactive.resource.NoResourceFoundException;
/**
* @author lengleng
@@ -30,6 +26,7 @@ import org.springframework.web.reactive.resource.NoResourceFoundException;
@Order(-1)
@Configuration
@RequiredArgsConstructor
+@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class GlobalExceptionConfiguration implements ErrorWebExceptionHandler {
private final ObjectMapper objectMapper;
@@ -62,24 +59,3 @@ public class GlobalExceptionConfiguration implements ErrorWebExceptionHandler {
}
}
-
-
-/**
- * 保持和低版本请求路径不存在的行为一致
- *
- * [Spring Boot
- * 3.2.0] 404 Not Found behavior #38733
- */
-@Slf4j
-@RestControllerAdvice
-class ReactiveNoResourceFoundHandler {
-
-
- @ExceptionHandler({NoResourceFoundException.class})
- @ResponseStatus(HttpStatus.NOT_FOUND)
- public R noResourceFoundException(NoResourceFoundException exception) {
- log.debug("请求路径 404 {}", exception.getMessage());
- return R.failed(exception.getMessage());
- }
-
-}
diff --git a/pigx-common/pigx-common-swagger/src/main/java/com/pig4cloud/pigx/common/swagger/config/OpenAPIMetadataConfiguration.java b/pigx-common/pigx-common-swagger/src/main/java/com/pig4cloud/pigx/common/swagger/config/OpenAPIMetadataConfiguration.java
index a73e2815b..ce2d488cd 100644
--- a/pigx-common/pigx-common-swagger/src/main/java/com/pig4cloud/pigx/common/swagger/config/OpenAPIMetadataConfiguration.java
+++ b/pigx-common/pigx-common-swagger/src/main/java/com/pig4cloud/pigx/common/swagger/config/OpenAPIMetadataConfiguration.java
@@ -20,6 +20,12 @@ public class OpenAPIMetadataConfiguration implements InitializingBean, Applicati
@Override
public void afterPropertiesSet() throws Exception {
+ String[] beanNamesForType = applicationContext.getBeanNamesForType(ServiceInstance.class);
+
+ if (beanNamesForType.length == 0) {
+ return;
+ }
+
ServiceInstance serviceInstance = applicationContext.getBean(ServiceInstance.class);
serviceInstance.getMetadata().put("spring-doc", path);
}
diff --git a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/pom.xml b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/pom.xml
index efef84cc0..2e8b6656c 100644
--- a/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/pom.xml
+++ b/pigx-flow/pigx-flow-engine/pigx-flow-engine-biz/pom.xml
@@ -123,16 +123,34 @@
DmJdbcDriver18
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- io.fabric8
- docker-maven-plugin
-
-
-
+
+
+ cloud
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ CLASSIC
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ false
+
+
+
+
+
+
diff --git a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/pom.xml b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/pom.xml
index 39d49bfb6..6c93ece3a 100644
--- a/pigx-flow/pigx-flow-task/pigx-flow-task-biz/pom.xml
+++ b/pigx-flow/pigx-flow-task/pigx-flow-task-biz/pom.xml
@@ -103,16 +103,34 @@
DmJdbcDriver18
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- io.fabric8
- docker-maven-plugin
-
-
-
+
+
+ cloud
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ CLASSIC
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ false
+
+
+
+
+
+
diff --git a/pigx-gateway/pom.xml b/pigx-gateway/pom.xml
index b12d46f21..fec321844 100644
--- a/pigx-gateway/pom.xml
+++ b/pigx-gateway/pom.xml
@@ -66,18 +66,6 @@
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
-
-
- io.springboot.plugin
- spring-boot-starter-captcha
- ${captcha.version}
-
-
-
- io.springboot.plugin
- captcha-core
- ${captcha.image.version}
-
org.springframework.boot
diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/GatewayConfigProperties.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/GatewayConfigProperties.java
deleted file mode 100644
index 23a4e8b13..000000000
--- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/GatewayConfigProperties.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.pig4cloud.pigx.gateway.config;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.cloud.context.config.annotation.RefreshScope;
-import org.springframework.stereotype.Component;
-
-/**
- * @author lengleng
- * @date 2020/10/2
- *
- * 网关通用配置文件
- */
-@Data
-@Component
-@RefreshScope
-@ConfigurationProperties("gateway")
-public class GatewayConfigProperties {
-
- /**
- * 网关解密登录前端密码 秘钥 {@link com.pig4cloud.pigx.gateway.filter.PasswordDecoderFilter}
- */
- public String encodeKey;
-
-}
diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/RouterFunctionConfiguration.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/RouterFunctionConfiguration.java
deleted file mode 100644
index 863ca4cb5..000000000
--- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/config/RouterFunctionConfiguration.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.gateway.config;
-
-import com.pig4cloud.pigx.gateway.handler.ImageCodeCheckHandler;
-import com.pig4cloud.pigx.gateway.handler.ImageCodeCreateHandler;
-import com.pig4cloud.pigx.gateway.handler.ImageCodeMathHandler;
-import lombok.AllArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.MediaType;
-import org.springframework.web.reactive.function.server.RequestPredicates;
-import org.springframework.web.reactive.function.server.RouterFunction;
-import org.springframework.web.reactive.function.server.RouterFunctions;
-
-/**
- * @author lengleng
- * @date 2018/7/5 路由配置信息
- */
-@Slf4j
-@Configuration
-@AllArgsConstructor
-public class RouterFunctionConfiguration {
-
- private final ImageCodeCheckHandler imageCodeCheckHandler;
-
- private final ImageCodeCreateHandler imageCodeCreateHandler;
-
- private final ImageCodeMathHandler imageCodeMathHandler;
-
- @Bean
- public RouterFunction routerFunction() {
- return RouterFunctions
- .route(RequestPredicates.path("/code/create").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
- imageCodeCreateHandler)
- .andRoute(RequestPredicates.path("/code/image").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
- imageCodeMathHandler)
- .andRoute(RequestPredicates.POST("/code/check").and(RequestPredicates.accept(MediaType.ALL)),
- imageCodeCheckHandler);
-
- }
-
-}
diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PasswordDecoderFilter.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PasswordDecoderFilter.java
deleted file mode 100644
index 43695920f..000000000
--- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/PasswordDecoderFilter.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.gateway.filter;
-
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.Mode;
-import cn.hutool.crypto.Padding;
-import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.symmetric.AES;
-import cn.hutool.http.HttpUtil;
-import cn.hutool.json.JSONObject;
-import cn.hutool.json.JSONUtil;
-import com.pig4cloud.pigx.common.core.constant.CacheConstants;
-import com.pig4cloud.pigx.common.core.constant.CommonConstants;
-import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
-import com.pig4cloud.pigx.common.core.constant.enums.EncFlagTypeEnum;
-import com.pig4cloud.pigx.common.core.util.WebUtils;
-import com.pig4cloud.pigx.gateway.config.GatewayConfigProperties;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.cloud.gateway.filter.GatewayFilter;
-import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
-import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
-import org.springframework.cloud.gateway.support.BodyInserterContext;
-import org.springframework.core.io.buffer.DataBuffer;
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.codec.HttpMessageReader;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
-import org.springframework.stereotype.Component;
-import org.springframework.web.reactive.function.BodyInserter;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.server.HandlerStrategies;
-import org.springframework.web.reactive.function.server.ServerRequest;
-import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-import java.nio.charset.Charset;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-
-/**
- * @author lengleng
- * @date 2020/1/8 密码解密工具类
- *
- * 参考 ModifyRequestBodyGatewayFilterFactory 实现
- */
-@Slf4j
-@Component
-@RequiredArgsConstructor
-@SuppressWarnings("all")
-public class PasswordDecoderFilter extends AbstractGatewayFilterFactory {
-
- private final List> messageReaders = HandlerStrategies.withDefaults().messageReaders();
-
- private static final String PASSWORD = "password";
-
- private static final String KEY_ALGORITHM = "AES";
-
- private final StringRedisTemplate redisTemplate;
-
- private final GatewayConfigProperties gatewayConfig;
-
- static {
- // 关闭hutool 强制关闭Bouncy Castle库的依赖
- SecureUtil.disableBouncyCastle();
- }
-
- @Override
- public GatewayFilter apply(Object config) {
- return (exchange, chain) -> {
- ServerHttpRequest request = exchange.getRequest();
- // 1. 不是登录请求,直接向下执行
- if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL)) {
- return chain.filter(exchange);
- }
-
- // 2. 刷新token类型,直接向下执行
- String grantType = request.getQueryParams().getFirst("grant_type");
- if (StrUtil.equals(SecurityConstants.REFRESH_TOKEN, grantType)) {
- return chain.filter(exchange);
- }
-
- // 3. 判断客户端是否需要解密,明文传输直接向下执行
- if (!isEncClient(request)) {
- return chain.filter(exchange);
- }
-
- // 4. 前端加密密文解密逻辑
- Class inClass = String.class;
- Class outClass = String.class;
- ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders);
-
- // 解密生成新的报文
- Mono> modifiedBody = serverRequest.bodyToMono(inClass).flatMap(decryptAES());
-
- BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass);
- HttpHeaders headers = new HttpHeaders();
- headers.putAll(exchange.getRequest().getHeaders());
- headers.remove(HttpHeaders.CONTENT_LENGTH);
-
- headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
- CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
- return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
- ServerHttpRequest decorator = decorate(exchange, headers, outputMessage);
- return chain.filter(exchange.mutate().request(decorator).build());
- }));
- };
- }
-
- /**
- * 根据请求的clientId 查询客户端配置是否是加密传输
- * @param request 请求上下文
- * @return true 加密传输 、 false 原文传输
- */
- private boolean isEncClient(ServerHttpRequest request) {
- String header = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
- String clientId = WebUtils.extractClientId(header).orElse(null);
- // 获取租户拼接区分租户的key
- String tenantId = request.getHeaders().getFirst(CommonConstants.TENANT_ID);
- String key = String.format("%s:%s:%s", StrUtil.isBlank(tenantId) ? CommonConstants.TENANT_ID_1 : tenantId,
- CacheConstants.CLIENT_FLAG, clientId);
-
- String val = redisTemplate.opsForValue().get(key);
-
- // 当配置不存在时,默认需要解密
- if (val == null) {
- return true;
- }
-
- JSONObject information = JSONUtil.parseObj(val);
- if (StrUtil.equals(EncFlagTypeEnum.NO.getType(), information.getStr(CommonConstants.ENC_FLAG))) {
- return false;
- }
- return true;
- }
-
- /**
- * 原文解密
- * @return
- */
- private Function decryptAES() {
- return s -> {
- // 构建前端对应解密AES 因子
- AES aes = new AES(Mode.CFB, Padding.NoPadding,
- new SecretKeySpec(gatewayConfig.getEncodeKey().getBytes(), KEY_ALGORITHM),
- new IvParameterSpec(gatewayConfig.getEncodeKey().getBytes()));
-
- // 获取请求密码并解密
- Map inParamsMap = HttpUtil.decodeParamMap((String) s, CharsetUtil.CHARSET_UTF_8);
- if (inParamsMap.containsKey(PASSWORD)) {
- String password = aes.decryptStr(inParamsMap.get(PASSWORD));
- // 返回修改后报文字符
- inParamsMap.put(PASSWORD, password);
- }
- else {
- log.error("非法请求数据:{}", s);
- }
-
- // 使用
- return Mono.just(HttpUtil.toParams(inParamsMap, Charset.defaultCharset(), true));
- };
- }
-
- /**
- * 报文转换
- * @return
- */
- private ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers,
- CachedBodyOutputMessage outputMessage) {
- return new ServerHttpRequestDecorator(exchange.getRequest()) {
- @Override
- public HttpHeaders getHeaders() {
- long contentLength = headers.getContentLength();
- HttpHeaders httpHeaders = new HttpHeaders();
- httpHeaders.putAll(super.getHeaders());
- if (contentLength > 0) {
- httpHeaders.setContentLength(contentLength);
- }
- else {
- httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
- }
- return httpHeaders;
- }
-
- @Override
- public Flux getBody() {
- return outputMessage.getBody();
- }
- };
- }
-
-}
diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java
deleted file mode 100644
index 79af25807..000000000
--- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/filter/ValidateCodeGatewayFilter.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.gateway.filter;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONObject;
-import cn.hutool.json.JSONUtil;
-import com.anji.captcha.model.vo.CaptchaVO;
-import com.anji.captcha.service.CaptchaService;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.pig4cloud.pigx.common.core.constant.CacheConstants;
-import com.pig4cloud.pigx.common.core.constant.CommonConstants;
-import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
-import com.pig4cloud.pigx.common.core.constant.enums.CaptchaFlagTypeEnum;
-import com.pig4cloud.pigx.common.core.exception.ValidateCodeException;
-import com.pig4cloud.pigx.common.core.util.R;
-import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
-import com.pig4cloud.pigx.common.core.util.WebUtils;
-import lombok.AllArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.cloud.gateway.filter.GatewayFilter;
-import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpResponse;
-import org.springframework.stereotype.Component;
-import reactor.core.publisher.Mono;
-
-/**
- * @author lengleng
- * @date 2020/5/19 登录逻辑验证码处理
- */
-@Slf4j
-@Component
-@AllArgsConstructor
-@SuppressWarnings("all")
-public class ValidateCodeGatewayFilter extends AbstractGatewayFilterFactory {
-
- private final StringRedisTemplate redisTemplate;
-
- private final ObjectMapper objectMapper;
-
- @Override
- public GatewayFilter apply(Object config) {
- return (exchange, chain) -> {
- ServerHttpRequest request = exchange.getRequest();
-
- // 不是登录请求直接向下执行
- if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL)) {
- return chain.filter(exchange);
- }
-
- // 刷新token,直接向下执行
- String grantType = request.getQueryParams().getFirst("grant_type");
- if (StrUtil.equals(SecurityConstants.REFRESH_TOKEN, grantType)) {
- return chain.filter(exchange);
- }
-
- // mobile模式, 如果请求不包含mobile 参数直接
- String mobile = request.getQueryParams().getFirst(SecurityConstants.GRANT_MOBILE);
- if (StrUtil.equals(SecurityConstants.GRANT_MOBILE, grantType) && StrUtil.isBlank(mobile)) {
- throw new ValidateCodeException();
- }
-
- // mobile模式, 社交登录模式不校验验证码直接跳过
- if (StrUtil.equals(SecurityConstants.GRANT_MOBILE, grantType) && !StrUtil.contains(mobile, "SMS")) {
- return chain.filter(exchange);
- }
-
- // 判断客户端是否跳过检验
- if (!isCheckCaptchaClient(request)) {
- return chain.filter(exchange);
- }
-
- try {
- // 校验验证码
- checkCode(request);
- }
- catch (Exception e) {
- ServerHttpResponse response = exchange.getResponse();
- response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
- response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
- try {
- return response.writeWith(Mono
- .just(response.bufferFactory().wrap(objectMapper.writeValueAsBytes(R.failed(e.getMessage())))));
- }
- catch (JsonProcessingException e1) {
- log.error("对象输出异常", e1);
- }
- }
-
- return chain.filter(exchange);
- };
- }
-
- /**
- * 是否需要校验客户端,根据client 查询客户端配置
- * @param request 请求
- * @return true 需要校验, false 不需要校验
- */
- private boolean isCheckCaptchaClient(ServerHttpRequest request) {
- String header = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
- String clientId = WebUtils.extractClientId(header).orElse(null);
- // 获取租户拼接区分租户的key
- String tenantId = request.getHeaders().getFirst(CommonConstants.TENANT_ID);
- String key = String.format("%s:%s:%s", StrUtil.isBlank(tenantId) ? CommonConstants.TENANT_ID_1 : tenantId,
- CacheConstants.CLIENT_FLAG, clientId);
-
- String val = redisTemplate.opsForValue().get(key);
-
- // 当配置不存在时,不用校验
- if (val == null) {
- return false;
- }
-
- JSONObject information = JSONUtil.parseObj(val);
- if (StrUtil.equals(CaptchaFlagTypeEnum.OFF.getType(), information.getStr(CommonConstants.CAPTCHA_FLAG))) {
- return false;
- }
- return true;
- }
-
- /**
- * 检查code
- * @param request
- */
- @SneakyThrows
- private void checkCode(ServerHttpRequest request) {
- String code = request.getQueryParams().getFirst("code");
-
- if (StrUtil.isBlank(code)) {
- throw new ValidateCodeException("验证码不能为空");
- }
-
- String randomStr = request.getQueryParams().getFirst("randomStr");
-
- // 若是滑块登录
- if (CommonConstants.IMAGE_CODE_TYPE.equalsIgnoreCase(randomStr)) {
- CaptchaService captchaService = SpringContextHolder.getBean(CaptchaService.class);
- CaptchaVO vo = new CaptchaVO();
- vo.setCaptchaVerification(code);
- vo.setCaptchaType(CommonConstants.IMAGE_CODE_TYPE);
- if (!captchaService.verification(vo).isSuccess()) {
- throw new ValidateCodeException("验证码不能为空");
- }
- return;
- }
-
- // https://gitee.com/log4j/pig/issues/IWA0D
- String mobile = request.getQueryParams().getFirst("mobile");
- if (StrUtil.isNotBlank(mobile)) {
- randomStr = mobile;
- }
-
- String key = CacheConstants.DEFAULT_CODE_KEY + randomStr;
- if (!redisTemplate.hasKey(key)) {
- throw new ValidateCodeException("验证码不合法");
- }
-
- String saveCode = redisTemplate.opsForValue().get(key);
-
- if (saveCode == null) {
- throw new ValidateCodeException("验证码不合法");
- }
-
- if (StrUtil.isBlank(saveCode)) {
- redisTemplate.delete(key);
- throw new ValidateCodeException("验证码不合法");
- }
-
- if (!StrUtil.equals(saveCode, code)) {
- redisTemplate.delete(key);
- throw new ValidateCodeException("验证码不合法");
- }
-
- redisTemplate.delete(key);
- }
-
-}
diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCheckHandler.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCheckHandler.java
deleted file mode 100644
index aa4d37d70..000000000
--- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCheckHandler.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.gateway.handler;
-
-import com.anji.captcha.model.common.ResponseModel;
-import com.anji.captcha.model.vo.CaptchaVO;
-import com.anji.captcha.service.CaptchaService;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.pig4cloud.pigx.common.core.constant.CommonConstants;
-import com.pig4cloud.pigx.common.core.util.R;
-import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Component;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.server.HandlerFunction;
-import org.springframework.web.reactive.function.server.ServerRequest;
-import org.springframework.web.reactive.function.server.ServerResponse;
-import reactor.core.publisher.Mono;
-
-/**
- * @author lengleng
- * @date 2020/5/19 验证码生成逻辑处理类
- */
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class ImageCodeCheckHandler implements HandlerFunction {
-
- private final ObjectMapper objectMapper;
-
- @Override
- @SneakyThrows
- public Mono handle(ServerRequest request) {
- CaptchaVO vo = new CaptchaVO();
- vo.setPointJson(request.queryParam("pointJson").get());
- vo.setToken(request.queryParam("token").get());
- vo.setCaptchaType(CommonConstants.IMAGE_CODE_TYPE);
-
- CaptchaService captchaService = SpringContextHolder.getBean(CaptchaService.class);
- ResponseModel responseModel = captchaService.check(vo);
-
- return ServerResponse.status(HttpStatus.OK)
- .contentType(MediaType.APPLICATION_JSON)
- .body(BodyInserters.fromValue(objectMapper.writeValueAsString(R.ok(responseModel))));
- }
-
-}
diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCreateHandler.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCreateHandler.java
deleted file mode 100644
index a65a38a1b..000000000
--- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeCreateHandler.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2018-2025, lengleng All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the pig4cloud.com developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: lengleng (wangiegie@gmail.com)
- */
-
-package com.pig4cloud.pigx.gateway.handler;
-
-import com.anji.captcha.model.common.ResponseModel;
-import com.anji.captcha.model.vo.CaptchaVO;
-import com.anji.captcha.service.CaptchaService;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.pig4cloud.pigx.common.core.constant.CommonConstants;
-import com.pig4cloud.pigx.common.core.util.R;
-import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
-import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Component;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.server.HandlerFunction;
-import org.springframework.web.reactive.function.server.ServerRequest;
-import org.springframework.web.reactive.function.server.ServerResponse;
-import reactor.core.publisher.Mono;
-
-/**
- * @author lengleng
- * @date 2020/5/19 验证码生成逻辑处理类
- */
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class ImageCodeCreateHandler implements HandlerFunction {
-
- private final ObjectMapper objectMapper;
-
- @Override
- @SneakyThrows
- public Mono handle(ServerRequest serverRequest) {
- CaptchaVO vo = new CaptchaVO();
- vo.setCaptchaType(CommonConstants.IMAGE_CODE_TYPE);
- CaptchaService captchaService = SpringContextHolder.getBean(CaptchaService.class);
- ResponseModel responseModel = captchaService.get(vo);
-
- return ServerResponse.status(HttpStatus.OK)
- .contentType(MediaType.APPLICATION_JSON)
- .body(BodyInserters.fromValue(objectMapper.writeValueAsString(R.ok(responseModel))));
- }
-
-}
diff --git a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeMathHandler.java b/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeMathHandler.java
deleted file mode 100755
index 9d91c6ff2..000000000
--- a/pigx-gateway/src/main/java/com/pig4cloud/pigx/gateway/handler/ImageCodeMathHandler.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.pig4cloud.pigx.gateway.handler;
-
-import com.pig4cloud.pigx.common.core.constant.CacheConstants;
-import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
-import io.springboot.captcha.ArithmeticCaptcha;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.core.io.ByteArrayResource;
-import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Component;
-import org.springframework.util.FastByteArrayOutputStream;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.server.HandlerFunction;
-import org.springframework.web.reactive.function.server.ServerRequest;
-import org.springframework.web.reactive.function.server.ServerResponse;
-import reactor.core.publisher.Mono;
-
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author lengleng
- * @date 2023-09-29 数据验证码实现
- */
-@Slf4j
-@Component
-@RequiredArgsConstructor
-public class ImageCodeMathHandler implements HandlerFunction {
-
- private static final Integer DEFAULT_IMAGE_WIDTH = 100;
-
- private static final Integer DEFAULT_IMAGE_HEIGHT = 40;
-
- private final StringRedisTemplate redisTemplate;
-
- @Override
- public Mono handle(ServerRequest serverRequest) {
- ArithmeticCaptcha captcha = new ArithmeticCaptcha(DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT);
-
- String result = captcha.text();
-
- // 保存验证码信息
- Optional randomStr = serverRequest.queryParam("randomStr");
- randomStr.ifPresent(s -> redisTemplate.opsForValue()
- .set(CacheConstants.DEFAULT_CODE_KEY + s, result, SecurityConstants.CODE_TIME, TimeUnit.SECONDS));
-
- // 转换流信息写出
- FastByteArrayOutputStream os = new FastByteArrayOutputStream();
- captcha.out(os);
-
- return ServerResponse.status(HttpStatus.OK)
- .contentType(MediaType.IMAGE_JPEG)
- .body(BodyInserters.fromResource(new ByteArrayResource(os.toByteArray())));
- }
-
-}
diff --git a/pigx-gateway/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService b/pigx-gateway/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService
deleted file mode 100644
index 742abee62..000000000
--- a/pigx-gateway/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService
+++ /dev/null
@@ -1 +0,0 @@
-com.pig4cloud.pigx.gateway.config.CaptchaCacheServiceProvider
diff --git a/pigx-upms/pigx-upms-biz/pom.xml b/pigx-upms/pigx-upms-biz/pom.xml
index fa60af007..cb1eeb2d3 100644
--- a/pigx-upms/pigx-upms-biz/pom.xml
+++ b/pigx-upms/pigx-upms-biz/pom.xml
@@ -161,37 +161,38 @@
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
- repackage
-
+
+
+ cloud
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ CLASSIC
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
- CLASSIC
+ false
-
-
-
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
- true
-
-
-
- io.fabric8
- docker-maven-plugin
-
- false
-
-
-
+
+
+
+
+
+
+
src/main/resources
@@ -211,5 +212,4 @@
-
diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/PigxAdminApplication.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/PigxAdminApplication.java
index 0968550e3..3bbf726ca 100644
--- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/PigxAdminApplication.java
+++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/PigxAdminApplication.java
@@ -19,7 +19,6 @@
package com.pig4cloud.pigx.admin;
-import com.pig4cloud.pigx.common.feign.annotation.EnablePigxFeignClients;
import com.pig4cloud.pigx.common.security.annotation.EnablePigxResourceServer;
import com.pig4cloud.pigx.common.swagger.annotation.EnableOpenApi;
import org.springframework.boot.SpringApplication;
@@ -33,7 +32,6 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
* 用户统一管理系统
*/
@EnableOpenApi("admin")
-@EnablePigxFeignClients
@EnablePigxResourceServer
@EnableDiscoveryClient
@SpringBootApplication
diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTokenController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTokenController.java
index fe095d240..36564a00b 100644
--- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTokenController.java
+++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/SysTokenController.java
@@ -39,7 +39,7 @@ import java.util.Map;
*/
@RestController
@AllArgsConstructor
-@RequestMapping("/token")
+@RequestMapping("/sys-token")
@Tag(description = "token", name = "令牌管理模块")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class SysTokenController {
diff --git a/pigx-upms/pigx-upms-biz/src/main/resources/logback-spring.xml b/pigx-upms/pigx-upms-biz/src/main/resources/logback-spring.xml
index bacd3f9c6..3e292157f 100644
--- a/pigx-upms/pigx-upms-biz/src/main/resources/logback-spring.xml
+++ b/pigx-upms/pigx-upms-biz/src/main/resources/logback-spring.xml
@@ -60,7 +60,7 @@
-
+
diff --git a/pigx-visual/pigx-codegen/pom.xml b/pigx-visual/pigx-codegen/pom.xml
index 3eee54cd1..538475067 100755
--- a/pigx-visual/pigx-codegen/pom.xml
+++ b/pigx-visual/pigx-codegen/pom.xml
@@ -175,26 +175,34 @@
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
- true
-
-
-
- io.fabric8
- docker-maven-plugin
-
- false
-
-
-
-
+
+
+ cloud
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ CLASSIC
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ false
+
+
+
+
+
+
diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/PigxCodeGenApplication.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/PigxCodeGenApplication.java
index 5d376d85b..3e0270d90 100755
--- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/PigxCodeGenApplication.java
+++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/PigxCodeGenApplication.java
@@ -30,8 +30,8 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
* @date 2018/07/29 代码生成模块
*/
@EnableDynamicDataSource
-@EnableOpenApi("gen")
@EnablePigxFeignClients
+@EnableOpenApi("gen")
@EnableDiscoveryClient
@EnablePigxResourceServer
@SpringBootApplication
diff --git a/pigx-visual/pigx-daemon-quartz/pom.xml b/pigx-visual/pigx-daemon-quartz/pom.xml
index 863fab1f9..5bc9521c6 100644
--- a/pigx-visual/pigx-daemon-quartz/pom.xml
+++ b/pigx-visual/pigx-daemon-quartz/pom.xml
@@ -99,21 +99,37 @@
org.springframework.boot
spring-boot-starter-quartz
+
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- io.fabric8
- docker-maven-plugin
-
- false
-
-
-
-
+
+
+ cloud
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ CLASSIC
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ false
+
+
+
+
+
+
diff --git a/pigx-visual/pigx-mp-platform/pom.xml b/pigx-visual/pigx-mp-platform/pom.xml
index cc1c12d83..c71ab420a 100755
--- a/pigx-visual/pigx-mp-platform/pom.xml
+++ b/pigx-visual/pigx-mp-platform/pom.xml
@@ -115,26 +115,34 @@
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
- true
-
-
-
- io.fabric8
- docker-maven-plugin
-
- false
-
-
-
-
+
+
+ cloud
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ CLASSIC
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ false
+
+
+
+
+
+
diff --git a/pigx-visual/pigx-mp-platform/src/main/java/com/pig4cloud/pigx/mp/config/WxMpInitConfigRunner.java b/pigx-visual/pigx-mp-platform/src/main/java/com/pig4cloud/pigx/mp/config/WxMpInitConfigRunner.java
index c654dd614..ee9acdafd 100644
--- a/pigx-visual/pigx-mp-platform/src/main/java/com/pig4cloud/pigx/mp/config/WxMpInitConfigRunner.java
+++ b/pigx-visual/pigx-mp-platform/src/main/java/com/pig4cloud/pigx/mp/config/WxMpInitConfigRunner.java
@@ -15,7 +15,7 @@ import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.constant.WxMpEventConstants;
-import org.springframework.boot.web.context.WebServerInitializedEvent;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
@@ -88,7 +88,7 @@ public class WxMpInitConfigRunner {
@Async
@Order
- @EventListener({ WebServerInitializedEvent.class })
+ @EventListener({ ApplicationReadyEvent.class })
public void WebServerInit() {
this.initServices();
}
diff --git a/pigx-visual/pigx-pay-platform/pom.xml b/pigx-visual/pigx-pay-platform/pom.xml
index 536c5d11f..b24da75b6 100755
--- a/pigx-visual/pigx-pay-platform/pom.xml
+++ b/pigx-visual/pigx-pay-platform/pom.xml
@@ -141,33 +141,34 @@
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
- true
-
-
-
- org.apache.maven.plugins
- maven-deploy-plugin
-
- true
-
-
-
- io.fabric8
- docker-maven-plugin
-
- false
-
-
-
-
+
+
+ cloud
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+ CLASSIC
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ false
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 16bc9164b..5fceece20 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,7 +50,7 @@
7.0.0
2.0.0
3.0.0
- 2.0.9
+ 3.0.5
2.3
3.1
3.0.5
@@ -252,45 +252,9 @@
-
-
-
- rdc-releases
- https://packages.aliyun.com/maven/repository/2161442-release-DcBZC1/
-
-
- rdc-snapshots
- https://packages.aliyun.com/maven/repository/2161442-snapshot-FzKqZK/
-
-
-
-
-
- public
- aliyun nexus
- https://maven.aliyun.com/repository/public/
-
- true
-
-
-
-
-
-
- aliyun-plugin
- https://maven.aliyun.com/repository/public
-
- true
-
-
- false
-
-
-
-
- dev
+ cloud
dev
@@ -302,6 +266,12 @@
true
+
+ boot
+
+ pigx-boot
+
+