woody 11 mēneši atpakaļ
vecāks
revīzija
b6e6be53b7
21 mainītis faili ar 285 papildinājumiem un 131 dzēšanām
  1. 9 3
      framework-base/src/main/java/com/chelvc/framework/base/config/ContextConfigurer.java
  2. 97 14
      framework-base/src/main/java/com/chelvc/framework/base/context/ApplicationContextHolder.java
  3. 3 0
      framework-base/src/main/java/com/chelvc/framework/base/interceptor/GlobalExceptionInterceptor.java
  4. 3 1
      framework-base/src/main/java/com/chelvc/framework/base/interceptor/ResponseHandleInterceptor.java
  5. 10 0
      framework-base/src/main/java/com/chelvc/framework/base/interceptor/ResponseHandler.java
  6. 21 6
      framework-base/src/main/java/com/chelvc/framework/base/interceptor/ResponseWrapHandler.java
  7. 2 25
      framework-database/src/main/java/com/chelvc/framework/database/config/DatabaseConfigurer.java
  8. 29 0
      framework-database/src/main/java/com/chelvc/framework/database/config/RedisIdentifierGenerator.java
  9. 3 2
      framework-nacos/src/main/java/com/chelvc/framework/nacos/context/NacosContextHolder.java
  10. 1 0
      framework-oauth/pom.xml
  11. 32 14
      framework-oauth/src/main/java/com/chelvc/framework/oauth/config/OAuthConfigurer.java
  12. 5 18
      framework-oauth/src/main/java/com/chelvc/framework/oauth/token/RedisTokenValidator.java
  13. 28 0
      framework-oauth/src/main/java/com/chelvc/framework/oauth/token/TimestampTokenValidator.java
  14. 13 0
      framework-oauth/src/main/java/com/chelvc/framework/oauth/token/TokenValidator.java
  15. 1 1
      framework-security/src/main/java/com/chelvc/framework/security/context/SecurityContextHolder.java
  16. 9 24
      framework-security/src/main/java/com/chelvc/framework/security/interceptor/ControllerCryptoInterceptor.java
  17. 5 10
      framework-security/src/main/java/com/chelvc/framework/security/interceptor/SensitiveResponseInterceptor.java
  18. 3 3
      framework-upload/src/main/java/com/chelvc/framework/upload/support/DefaultUploadHandler.java
  19. 5 5
      framework-upload/src/main/java/com/chelvc/framework/upload/support/TencentUploadHandler.java
  20. 5 4
      framework-wechat/src/main/java/com/chelvc/framework/wechat/DefaultWechatPaymentHandler.java
  21. 1 1
      framework-wechat/src/main/java/com/chelvc/framework/wechat/DefaultWechatPublicHandler.java

+ 9 - 3
framework-base/src/main/java/com/chelvc/framework/base/config/ContextConfigurer.java

@@ -1,13 +1,13 @@
 package com.chelvc.framework.base.config;
 
 import java.util.List;
-import java.util.Map;
 
 import com.chelvc.framework.base.context.ApplicationContextHolder;
 import com.chelvc.framework.base.context.DefaultSessionFactory;
 import com.chelvc.framework.base.context.SessionFactory;
 import com.chelvc.framework.base.interceptor.ResponseHandleInterceptor;
 import com.chelvc.framework.base.interceptor.ResponseHandler;
+import com.chelvc.framework.base.interceptor.ResponseWrapHandler;
 import com.chelvc.framework.common.util.ObjectUtils;
 import com.google.common.collect.Lists;
 import org.springframework.beans.BeansException;
@@ -40,8 +40,8 @@ public class ContextConfigurer implements ApplicationContextAware {
         RequestResponseBodyMethodProcessor processor = CollectionUtils.isEmpty(valueHandlers) ? null :
                 valueHandlers.stream().filter(handler -> handler instanceof RequestResponseBodyMethodProcessor)
                         .map(handler -> (RequestResponseBodyMethodProcessor) handler).findFirst().orElse(null);
-        Map<String, ResponseHandler> beans = applicationContext.getBeansOfType(ResponseHandler.class);
-        List<ResponseHandler> responseHandlers = ApplicationContextHolder.order(beans.values());
+        List<ResponseHandler> responseHandlers =
+                ApplicationContextHolder.getOrderBeans(applicationContext, ResponseHandler.class);
         ResponseHandleInterceptor interceptor = new ResponseHandleInterceptor(processor, responseHandlers);
         List<HandlerMethodReturnValueHandler> handlers = Lists.newLinkedList();
         handlers.add(interceptor);
@@ -61,4 +61,10 @@ public class ContextConfigurer implements ApplicationContextAware {
     public SessionFactory sessionFactory() {
         return new DefaultSessionFactory();
     }
+
+    @Bean
+    @ConditionalOnMissingBean(ResponseWrapHandler.class)
+    public ResponseWrapHandler responseWrapHandler() {
+        return new ResponseWrapHandler();
+    }
 }

+ 97 - 14
framework-base/src/main/java/com/chelvc/framework/base/context/ApplicationContextHolder.java

@@ -196,7 +196,7 @@ public class ApplicationContextHolder implements ApplicationContextAware, Proper
             // application.yml
             YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
             yaml.setResources(resource);
-            properties = Objects.requireNonNull(yaml.getObject());
+            properties = yaml.getObject();
         } else {
             // application.properties
             properties = new Properties();
@@ -206,7 +206,7 @@ public class ApplicationContextHolder implements ApplicationContextAware, Proper
                 throw new RuntimeException(e);
             }
         }
-        return properties.getProperty(APPLICATION_NAME_PROPERTY);
+        return properties == null ? null : properties.getProperty(APPLICATION_NAME_PROPERTY);
     }
 
     /**
@@ -415,10 +415,22 @@ public class ApplicationContextHolder implements ApplicationContextAware, Proper
      * @param <T>  对象类型泛型
      * @return 对象实例
      */
-    public static <T> T getBean(Class<T> type) {
+    public static <T> T getBean(@NonNull Class<T> type) {
         return getBean(type, true);
     }
 
+    /**
+     * 获取对象实例
+     *
+     * @param applicationContext 应用上下文
+     * @param type               对象类型
+     * @param <T>                对象类型泛型
+     * @return 对象实例
+     */
+    public static <T> T getBean(@NonNull ApplicationContext applicationContext, @NonNull Class<T> type) {
+        return getBean(applicationContext, type, true);
+    }
+
     /**
      * 获取对象实例
      *
@@ -427,11 +439,22 @@ public class ApplicationContextHolder implements ApplicationContextAware, Proper
      * @param <T>      对象类型泛型
      * @return 对象实例
      */
-    public static <T> T getBean(Class<T> type, boolean required) {
+    public static <T> T getBean(@NonNull Class<T> type, boolean required) {
         ApplicationContext applicationContext = getApplicationContext(required);
-        if (applicationContext == null) {
-            return null;
-        }
+        return applicationContext == null ? null : getBean(applicationContext, type, required);
+    }
+
+    /**
+     * 获取对象实例
+     *
+     * @param applicationContext 应用上下文
+     * @param type               对象类型
+     * @param required           对象实例是否必须存在
+     * @param <T>                对象类型泛型
+     * @return 对象实例
+     */
+    public static <T> T getBean(@NonNull ApplicationContext applicationContext, @NonNull Class<T> type,
+                                boolean required) {
         try {
             return applicationContext.getBean(type);
         } catch (NoSuchBeanDefinitionException e) {
@@ -449,10 +472,22 @@ public class ApplicationContextHolder implements ApplicationContextAware, Proper
      * @param <T>  对象类型泛型
      * @return 对象实例
      */
-    public static <T> T getBean(String name) {
+    public static <T> T getBean(@NonNull String name) {
         return getBean(name, true);
     }
 
+    /**
+     * 获取对象实例
+     *
+     * @param applicationContext 应用上下文
+     * @param name               对象名称
+     * @param <T>                对象类型泛型
+     * @return 对象实例
+     */
+    public static <T> T getBean(@NonNull ApplicationContext applicationContext, @NonNull String name) {
+        return getBean(applicationContext, name, true);
+    }
+
     /**
      * 获取对象实例
      *
@@ -461,12 +496,23 @@ public class ApplicationContextHolder implements ApplicationContextAware, Proper
      * @param <T>      对象类型泛型
      * @return 对象实例
      */
-    @SuppressWarnings("unchecked")
-    public static <T> T getBean(String name, boolean required) {
+    public static <T> T getBean(@NonNull String name, boolean required) {
         ApplicationContext applicationContext = getApplicationContext(required);
-        if (applicationContext == null) {
-            return null;
-        }
+        return applicationContext == null ? null : getBean(applicationContext, name, required);
+    }
+
+    /**
+     * 获取对象实例
+     *
+     * @param applicationContext 应用上下文
+     * @param name               对象名称
+     * @param required           对象实例是否必须存在
+     * @param <T>                对象类型泛型
+     * @return 对象实例
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(@NonNull ApplicationContext applicationContext, @NonNull String name,
+                                boolean required) {
         try {
             return (T) applicationContext.getBean(name);
         } catch (NoSuchBeanDefinitionException e) {
@@ -485,7 +531,44 @@ public class ApplicationContextHolder implements ApplicationContextAware, Proper
      * @return 对象名称/实例映射表
      */
     public static <T> Map<String, T> getBeans(@NonNull Class<T> type) {
-        return getApplicationContext().getBeansOfType(type);
+        return getBeans(getApplicationContext(), type);
+    }
+
+    /**
+     * 获取对象名称/实例映射表
+     *
+     * @param applicationContext 应用上下文
+     * @param type               对象类型
+     * @param <T>                对象类型
+     * @return 对象名称/实例映射表
+     */
+    public static <T> Map<String, T> getBeans(@NonNull ApplicationContext applicationContext, @NonNull Class<T> type) {
+        return applicationContext.getBeansOfType(type);
+    }
+
+    /**
+     * 根据@Order注解获取排序Bean实例
+     *
+     * @param type 对象类型
+     * @param <T>  对象类型
+     * @return Bean对象实例列表
+     */
+    public static <T> List<T> getOrderBeans(@NonNull Class<? extends T> type) {
+        return getOrderBeans(getApplicationContext(), type);
+    }
+
+    /**
+     * 根据@Order注解获取排序Bean实例
+     *
+     * @param applicationContext 应用上下文
+     * @param type               对象类型
+     * @param <T>                对象类型
+     * @return Bean对象实例列表
+     */
+    public static <T> List<T> getOrderBeans(@NonNull ApplicationContext applicationContext,
+                                            @NonNull Class<? extends T> type) {
+        Map<String, ? extends T> beans = getBeans(applicationContext, type);
+        return ObjectUtils.isEmpty(beans) ? Collections.emptyList() : order(beans.values());
     }
 
     /**

+ 3 - 0
framework-base/src/main/java/com/chelvc/framework/base/interceptor/GlobalExceptionInterceptor.java

@@ -246,6 +246,9 @@ public class GlobalExceptionInterceptor extends AbstractErrorController implemen
         Result<?> result;
         if (status.is5xxServerError()) {
             result = Result.failure(ApplicationContextHolder.getMessage("Failure"));
+        } else if (status == HttpStatus.NOT_FOUND) {
+            result = Result.of(HttpStatus.NOT_FOUND.name(), null,
+                    ApplicationContextHolder.getMessage("Not.Found"));
         } else if (status == HttpStatus.UNAUTHORIZED) {
             result = Result.of(HttpStatus.UNAUTHORIZED.name(), null,
                     ApplicationContextHolder.getMessage("Unauthorized"));

+ 3 - 1
framework-base/src/main/java/com/chelvc/framework/base/interceptor/ResponseHandleInterceptor.java

@@ -35,7 +35,9 @@ public class ResponseHandleInterceptor implements HandlerMethodReturnValueHandle
     public void handleReturnValue(Object value, MethodParameter method, ModelAndViewContainer container,
                                   NativeWebRequest request) throws Exception {
         for (ResponseHandler handler : this.handlers) {
-            value = handler.handle(request, method, value);
+            if (handler.supports(method)) {
+                value = handler.handle(request, method, value);
+            }
         }
         this.processor.handleReturnValue(value, method, container, request);
     }

+ 10 - 0
framework-base/src/main/java/com/chelvc/framework/base/interceptor/ResponseHandler.java

@@ -10,6 +10,16 @@ import org.springframework.web.context.request.NativeWebRequest;
  * @date 2024/1/30
  */
 public interface ResponseHandler {
+    /**
+     * 判断当前处理器是否支持指定方法
+     *
+     * @param method 请求方法
+     * @return true/false
+     */
+    default boolean supports(MethodParameter method) {
+        return true;
+    }
+
     /**
      * 响应结果处理
      *

+ 21 - 6
framework-base/src/main/java/com/chelvc/framework/base/interceptor/ResponseWrapHandler.java

@@ -5,7 +5,6 @@ import com.chelvc.framework.base.context.ApplicationContextHolder;
 import com.chelvc.framework.base.context.Result;
 import org.springframework.core.MethodParameter;
 import org.springframework.core.annotation.Order;
-import org.springframework.stereotype.Component;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.context.request.NativeWebRequest;
@@ -17,7 +16,6 @@ import org.springframework.web.context.request.NativeWebRequest;
  * @date 2024/1/30
  */
 @Order
-@Component
 public class ResponseWrapHandler implements ResponseHandler {
     /**
      * 判断目标方法是否使用@ResponseBody注解
@@ -45,11 +43,28 @@ public class ResponseWrapHandler implements ResponseHandler {
         return annotation != null && annotation.enabled();
     }
 
+    /**
+     * 包装请求结果
+     *
+     * @param request 请求对象
+     * @param method  请求方法
+     * @param value   请求结果
+     * @return 请求结果对象实例
+     */
+    protected Result<?> wrap(NativeWebRequest request, MethodParameter method, Object value) {
+        if (value instanceof Result) {
+            return (Result<?>) value;
+        }
+        return Result.success(value, ApplicationContextHolder.getMessage("Success"));
+    }
+
+    @Override
+    public boolean supports(MethodParameter method) {
+        return this.isResponseBodyMethod(method) && this.isResponseWrappingMethod(method);
+    }
+
     @Override
     public Object handle(NativeWebRequest request, MethodParameter method, Object value) {
-        if (!(value instanceof Result) && this.isResponseBodyMethod(method) && this.isResponseWrappingMethod(method)) {
-            return Result.success(value, ApplicationContextHolder.getMessage("Success"));
-        }
-        return value;
+        return this.wrap(request, method, value);
     }
 }

+ 2 - 25
framework-database/src/main/java/com/chelvc/framework/database/config/DatabaseConfigurer.java

@@ -1,10 +1,8 @@
 package com.chelvc.framework.database.config;
 
-import java.util.Map;
 import java.util.function.Supplier;
 
 import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
-import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
 import com.baomidou.mybatisplus.core.injector.ISqlInjector;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
@@ -18,8 +16,6 @@ import com.chelvc.framework.common.model.File;
 import com.chelvc.framework.common.model.Modification;
 import com.chelvc.framework.common.model.Period;
 import com.chelvc.framework.common.model.Region;
-import com.chelvc.framework.common.util.IdentityUtils;
-import com.chelvc.framework.common.util.ObjectUtils;
 import com.chelvc.framework.database.context.Transactor;
 import com.chelvc.framework.database.handler.FileTypeHandler;
 import com.chelvc.framework.database.handler.ModificationTypeHandler;
@@ -28,14 +24,11 @@ import com.chelvc.framework.database.handler.RegionTypeHandler;
 import com.chelvc.framework.database.interceptor.DeletedIsolateInterceptor;
 import com.chelvc.framework.database.interceptor.EnvIsolateInterceptor;
 import com.chelvc.framework.database.support.EnhanceSqlInjector;
-import com.chelvc.framework.redis.context.RedisContextHolder;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
 import org.apache.ibatis.type.JdbcType;
 import org.apache.ibatis.type.TypeHandlerRegistry;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -47,7 +40,6 @@ import org.springframework.transaction.annotation.Transactional;
  * @author Woody
  * @date 2024/1/30
  */
-@Slf4j
 @Configuration
 @RequiredArgsConstructor(onConstructor = @__(@Autowired))
 public class DatabaseConfigurer {
@@ -92,28 +84,13 @@ public class DatabaseConfigurer {
         return new EnhanceSqlInjector();
     }
 
-    @Bean
-    @ConditionalOnClass(name = "com.chelvc.framework.redis.context.RedisContextHolder")
-    public IdentifierGenerator identifierGenerator() {
-        return entity -> {
-            try {
-                return RedisContextHolder.identity();
-            } catch (Exception e) {
-                log.warn("Redis identifier generate failed: {}", e.getMessage());
-                return IdentityUtils.generate();
-            }
-        };
-    }
-
     @Bean
     public MybatisPlusInterceptor mybatisPlusInterceptor() {
         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
 
         // 设置自定义租户隔离拦截器
-        Map<String, InnerInterceptor> inners = this.applicationContext.getBeansOfType(InnerInterceptor.class);
-        if (ObjectUtils.notEmpty(inners)) {
-            ApplicationContextHolder.order(inners.values(), interceptor::addInnerInterceptor);
-        }
+        ApplicationContextHolder.getOrderBeans(this.applicationContext, InnerInterceptor.class)
+                .forEach(interceptor::addInnerInterceptor);
 
         // 设置数据环境隔离过滤拦截器
         interceptor.addInnerInterceptor(new TenantLineInnerInterceptor() {

+ 29 - 0
framework-database/src/main/java/com/chelvc/framework/database/config/RedisIdentifierGenerator.java

@@ -0,0 +1,29 @@
+package com.chelvc.framework.database.config;
+
+import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+import com.chelvc.framework.common.util.IdentityUtils;
+import com.chelvc.framework.redis.context.RedisContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.stereotype.Component;
+
+/**
+ * 基于Redis分布式ID生成器实现
+ *
+ * @author Woody
+ * @date 2024/6/23
+ */
+@Slf4j
+@Component
+@ConditionalOnClass(RedisContextHolder.class)
+public class RedisIdentifierGenerator implements IdentifierGenerator {
+    @Override
+    public Number nextId(Object entity) {
+        try {
+            return RedisContextHolder.identity();
+        } catch (Exception e) {
+            log.warn("Redis identifier generate failed: {}", e.getMessage());
+            return IdentityUtils.generate();
+        }
+    }
+}

+ 3 - 2
framework-nacos/src/main/java/com/chelvc/framework/nacos/context/NacosContextHolder.java

@@ -2,7 +2,6 @@ package com.chelvc.framework.nacos.context;
 
 import java.util.Collections;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Properties;
 import java.util.stream.Collectors;
 
@@ -13,6 +12,7 @@ import com.alibaba.nacos.api.common.Constants;
 import com.alibaba.nacos.api.config.ConfigService;
 import com.alibaba.nacos.api.exception.NacosException;
 import com.chelvc.framework.base.context.ApplicationContextHolder;
+import com.chelvc.framework.common.util.AssertUtils;
 import com.chelvc.framework.common.util.ObjectUtils;
 import com.chelvc.framework.common.util.StringUtils;
 import com.google.common.collect.ImmutableMap;
@@ -47,7 +47,8 @@ public final class NacosContextHolder {
     public static String getConfigId() {
         String id = ApplicationContextHolder.getProperty("nacos.config.id");
         if (StringUtils.isEmpty(id)) {
-            return Objects.requireNonNull(ApplicationContextHolder.getApplicationName());
+            String name = ApplicationContextHolder.getApplicationName();
+            return AssertUtils.nonempty(name, () -> "Application name is missing");
         }
         return id;
     }

+ 1 - 0
framework-oauth/pom.xml

@@ -23,6 +23,7 @@
             <groupId>com.chelvc.framework</groupId>
             <artifactId>framework-redis</artifactId>
             <version>${framework-redis.version}</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.springframework.security</groupId>

+ 32 - 14
framework-oauth/src/main/java/com/chelvc/framework/oauth/config/OAuthConfigurer.java

@@ -1,9 +1,9 @@
 package com.chelvc.framework.oauth.config;
 
 import java.lang.reflect.Method;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.Set;
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
@@ -15,11 +15,14 @@ import com.chelvc.framework.base.context.SessionContextHolder;
 import com.chelvc.framework.base.util.HttpUtils;
 import com.chelvc.framework.base.util.SpringUtils;
 import com.chelvc.framework.common.util.AESUtils;
+import com.chelvc.framework.common.util.AssertUtils;
 import com.chelvc.framework.common.util.ObjectUtils;
 import com.chelvc.framework.common.util.StringUtils;
 import com.chelvc.framework.oauth.annotation.Authorize;
 import com.chelvc.framework.oauth.context.OAuthContextHolder;
-import com.chelvc.framework.oauth.token.RedisTokenValidator;
+import com.chelvc.framework.oauth.token.TimestampTokenValidator;
+import com.chelvc.framework.oauth.token.TokenValidator;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -37,8 +40,12 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
 import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
 import org.springframework.security.oauth2.core.OAuth2Error;
+import org.springframework.security.oauth2.core.OAuth2TokenValidator;
+import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
+import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.security.oauth2.jwt.JwtDecoder;
 import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
 import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
@@ -67,12 +74,20 @@ public class OAuthConfigurer extends WebSecurityConfigurerAdapter {
     @Bean
     public JwtDecoder jwtDecoder() {
         // 构建JWT解码器实例
-        String secret = Objects.requireNonNull(this.properties.getSecret());
+        String secret = AssertUtils.nonempty(this.properties.getSecret(), () -> "OAuth secret is missing");
         SecretKey key = new SecretKeySpec(secret.getBytes(), AESUtils.ALGORITHM);
         NimbusJwtDecoder decoder = NimbusJwtDecoder.withSecretKey(key).build();
 
-        // 设置令牌验证器
-        decoder.setJwtValidator(new RedisTokenValidator());
+        // 添加自定义令牌验证器
+        Collection<OAuth2TokenValidator<Jwt>> validators = Lists.newLinkedList();
+        validators.add(new TimestampTokenValidator());
+        validators.addAll(ApplicationContextHolder.getOrderBeans(this.applicationContext, TokenValidator.class));
+        validators.add(jwt -> {
+            // 初始化会话主体信息
+            OAuthContextHolder.initializeSessionPrincipal(jwt);
+            return OAuth2TokenValidatorResult.success();
+        });
+        decoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>(validators));
         return decoder;
     }
 
@@ -142,10 +157,12 @@ public class OAuthConfigurer extends WebSecurityConfigurerAdapter {
             http.logout().addLogoutHandler(this.logoutHandler);
         }
 
-        // 排除认证
-        Set<String> ignores = Sets.newHashSet();
+        // 如果排除认证配置非空,则其他资源全部守保护
         if (ObjectUtils.notEmpty(this.properties.getIgnores())) {
-            ignores.addAll(this.properties.getIgnores());
+            String[] ignores = this.properties.getIgnores().toArray(new String[0]);
+            http.authorizeRequests().antMatchers(ignores).permitAll();
+            http.authorizeRequests().anyRequest().authenticated();
+            return;
         }
 
         // 判断是否启用多服务MVC配置,如果包含则获取所有服务资源对象
@@ -153,7 +170,8 @@ public class OAuthConfigurer extends WebSecurityConfigurerAdapter {
         List<Resource> resources = multiserver ?
                 ApplicationContextHolder.getApplicationResources() : Collections.emptyList();
 
-        // 将所有使用@Authorize注解并且enabled = true的接口地址排除认证
+        // 将所有使用@Authorize注解并且enabled=true的接口地址加入认证
+        Set<String> authenticates = Sets.newHashSet();
         ApplicationContextHolder.lookupControllers(this.applicationContext).forEach(controller -> {
             Class<?> clazz = AopProxyUtils.ultimateTargetClass(controller);
 
@@ -168,16 +186,16 @@ public class OAuthConfigurer extends WebSecurityConfigurerAdapter {
             for (Method method : clazz.getDeclaredMethods()) {
                 Authorize authorize = method.getAnnotation(Authorize.class);
                 if ((authorize != null || (authorize = clazz.getAnnotation(Authorize.class)) != null)
-                        && !authorize.enabled()) {
+                        && authorize.enabled()) {
                     for (String api : SpringUtils.getApis(method)) {
-                        ignores.add(HttpUtils.uri(prefix, api));
+                        authenticates.add(HttpUtils.uri(prefix, api));
                     }
                 }
             }
         });
-        if (ObjectUtils.notEmpty(ignores)) {
-            http.authorizeRequests().antMatchers(ignores.toArray(new String[0])).permitAll();
+        if (ObjectUtils.notEmpty(authenticates)) {
+            http.authorizeRequests().antMatchers(authenticates.toArray(new String[0])).authenticated();
         }
-        http.authorizeRequests().anyRequest().authenticated();
+        http.authorizeRequests().anyRequest().permitAll();
     }
 }

+ 5 - 18
framework-oauth/src/main/java/com/chelvc/framework/oauth/token/RedisTokenValidator.java

@@ -12,12 +12,12 @@ import com.chelvc.framework.common.util.StringUtils;
 import com.chelvc.framework.oauth.context.OAuthContextHolder;
 import com.chelvc.framework.redis.context.RedisContextHolder;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
 import org.springframework.security.oauth2.core.OAuth2Error;
-import org.springframework.security.oauth2.core.OAuth2TokenValidator;
 import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
 import org.springframework.security.oauth2.jwt.Jwt;
-import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
+import org.springframework.stereotype.Component;
 
 /**
  * 基于Redis的令牌验证器实现
@@ -26,18 +26,11 @@ import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
  * @date 2024/1/30
  */
 @Slf4j
-public class RedisTokenValidator implements OAuth2TokenValidator<Jwt> {
-    private final JwtTimestampValidator timestampValidator = new JwtTimestampValidator();
-
+@Component
+@ConditionalOnClass(RedisContextHolder.class)
+public class RedisTokenValidator implements TokenValidator {
     @Override
     public OAuth2TokenValidatorResult validate(Jwt jwt) {
-        // 校验令牌是否过期
-        if (this.timestampValidator.validate(jwt).hasErrors()) {
-            throw new OAuth2AuthenticationException(new OAuth2Error(
-                    "TOKEN_EXPIRED", ApplicationContextHolder.getMessage("Token.Expired"), null
-            ));
-        }
-
         // 基于Redis令牌有效性校验
         String key = OAuthContextHolder.key(OAuthContextHolder.getId(jwt));
         Collection<Object> fields = Arrays.asList(
@@ -49,9 +42,6 @@ public class RedisTokenValidator implements OAuth2TokenValidator<Jwt> {
             values = RedisContextHolder.getDefaultTemplate().opsForHash().multiGet(key, fields);
         } catch (Exception e) {
             log.warn("Redis token validate failed: {}", e.getMessage());
-
-            // 初始化会话主体信息
-            OAuthContextHolder.initializeSessionPrincipal(jwt);
             return OAuth2TokenValidatorResult.success();
         }
         String scope = ObjectUtils.size(values) > 0 ? (String) StringUtils.ifEmpty(values.get(0), (String) null) : null;
@@ -72,9 +62,6 @@ public class RedisTokenValidator implements OAuth2TokenValidator<Jwt> {
             String message = ApplicationContextHolder.getMessage("Scope.Changed", new Object[]{arg});
             throw new OAuth2AuthenticationException(new OAuth2Error("SCOPE_CHANGED", message, null));
         }
-
-        // 初始化会话主体信息
-        OAuthContextHolder.initializeSessionPrincipal(jwt);
         return OAuth2TokenValidatorResult.success();
     }
 }

+ 28 - 0
framework-oauth/src/main/java/com/chelvc/framework/oauth/token/TimestampTokenValidator.java

@@ -0,0 +1,28 @@
+package com.chelvc.framework.oauth.token;
+
+import com.chelvc.framework.base.context.ApplicationContextHolder;
+import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
+import org.springframework.security.oauth2.core.OAuth2Error;
+import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
+
+/**
+ * 令牌时间戳验证器实现
+ *
+ * @author Woody
+ * @date 2024/6/23
+ */
+public class TimestampTokenValidator implements TokenValidator {
+    private final JwtTimestampValidator delegate = new JwtTimestampValidator();
+
+    @Override
+    public OAuth2TokenValidatorResult validate(Jwt jwt) {
+        if (this.delegate.validate(jwt).hasErrors()) {
+            throw new OAuth2AuthenticationException(new OAuth2Error(
+                    "TOKEN_EXPIRED", ApplicationContextHolder.getMessage("Token.Expired"), null
+            ));
+        }
+        return OAuth2TokenValidatorResult.success();
+    }
+}

+ 13 - 0
framework-oauth/src/main/java/com/chelvc/framework/oauth/token/TokenValidator.java

@@ -0,0 +1,13 @@
+package com.chelvc.framework.oauth.token;
+
+import org.springframework.security.oauth2.core.OAuth2TokenValidator;
+import org.springframework.security.oauth2.jwt.Jwt;
+
+/**
+ * 令牌验证器接口
+ *
+ * @author Woody
+ * @date 2024/6/23
+ */
+public interface TokenValidator extends OAuth2TokenValidator<Jwt> {
+}

+ 1 - 1
framework-security/src/main/java/com/chelvc/framework/security/context/SecurityContextHolder.java

@@ -154,7 +154,7 @@ public final class SecurityContextHolder {
      * @return 签名信息
      */
     public static String sign(@NonNull Session session, String payload) {
-        String secret = AssertUtils.nonempty(getProperties().getSecret(), () -> "secret is missing");
+        String secret = AssertUtils.nonempty(getProperties().getSecret(), () -> "Security secret is missing");
         String plaintext = secret + session.getPlatform() + session.getTerminal() + session.getVersion() +
                 session.getTimestamp() + payload;
         return CodecUtils.md5(plaintext);

+ 9 - 24
framework-security/src/main/java/com/chelvc/framework/security/interceptor/ControllerCryptoInterceptor.java

@@ -52,28 +52,6 @@ public class ControllerCryptoInterceptor extends RequestBodyAdviceAdapter implem
         return annotation;
     }
 
-    /**
-     * 判断是否是输入加密方法
-     *
-     * @param method 目标方法
-     * @return true/false
-     */
-    private boolean isInputCryptoMethod(MethodParameter method) {
-        Crypto annotation = this.getCryptoAnnotation(method);
-        return annotation != null && annotation.input();
-    }
-
-    /**
-     * 判断是否是输出加密方法
-     *
-     * @param method 目标方法
-     * @return true/false
-     */
-    private boolean isOutputCryptoMethod(MethodParameter method) {
-        Crypto annotation = this.getCryptoAnnotation(method);
-        return annotation != null && annotation.output();
-    }
-
     /**
      * 获取消息密文
      *
@@ -89,9 +67,16 @@ public class ControllerCryptoInterceptor extends RequestBodyAdviceAdapter implem
         return Base64.decodeBase64(FileUtils.getBytes(input));
     }
 
+    @Override
+    public boolean supports(MethodParameter method) {
+        Crypto annotation = this.getCryptoAnnotation(method);
+        return annotation != null && annotation.output();
+    }
+
     @Override
     public boolean supports(MethodParameter method, Type type, Class<? extends HttpMessageConverter<?>> clazz) {
-        return this.isInputCryptoMethod(method);
+        Crypto annotation = this.getCryptoAnnotation(method);
+        return annotation != null && annotation.input();
     }
 
     @Override
@@ -121,7 +106,7 @@ public class ControllerCryptoInterceptor extends RequestBodyAdviceAdapter implem
 
     @Override
     public Object handle(NativeWebRequest request, MethodParameter method, Object value) {
-        if (value != null && this.isOutputCryptoMethod(method)) {
+        if (value != null) {
             Cipher cipher = SecurityContextHolder.getEncryptor();
             value = AESUtils.encrypt(cipher, JacksonContextHolder.serialize(value));
         }

+ 5 - 10
framework-security/src/main/java/com/chelvc/framework/security/interceptor/SensitiveResponseInterceptor.java

@@ -27,21 +27,16 @@ import org.springframework.web.context.request.NativeWebRequest;
 @Component
 @Order(Ordered.LOWEST_PRECEDENCE - 2)
 public class SensitiveResponseInterceptor implements ResponseHandler {
-    /**
-     * 判断是否是敏感数据方法
-     *
-     * @param method 目标方法
-     * @return true/false
-     */
-    private boolean isSensitiveMethod(MethodParameter method) {
-        return method.hasMethodAnnotation(Sensitive.class);
+    @Override
+    public boolean supports(MethodParameter method) {
+        return Objects.nonNull(method.getMethod()) && method.hasMethodAnnotation(Sensitive.class);
     }
 
     @Override
     @SuppressWarnings("unchecked")
     public Object handle(NativeWebRequest request, MethodParameter method, Object value) {
-        if (value == null || !this.isSensitiveMethod(method)) {
-            return value;
+        if (value == null) {
+            return null;
         }
         Cipher cipher = SecurityContextHolder.getEncryptor();
         Type type = Objects.requireNonNull(method.getMethod()).getGenericReturnType();

+ 3 - 3
framework-upload/src/main/java/com/chelvc/framework/upload/support/DefaultUploadHandler.java

@@ -3,9 +3,9 @@ package com.chelvc.framework.upload.support;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Objects;
 
 import com.chelvc.framework.base.util.HttpUtils;
+import com.chelvc.framework.common.util.AssertUtils;
 import com.chelvc.framework.common.util.FileUtils;
 import com.chelvc.framework.common.util.StringUtils;
 import com.chelvc.framework.upload.UploadHandler;
@@ -23,8 +23,8 @@ public class DefaultUploadHandler implements UploadHandler {
     private final String domain;
 
     public DefaultUploadHandler(@NonNull UploadProperties.Client properties) {
-        this.path = Objects.requireNonNull(properties.getPath());
-        this.domain = Objects.requireNonNull(properties.getDomain());
+        this.path = AssertUtils.nonempty(properties.getPath(), () -> "Local upload path is missing");
+        this.domain = AssertUtils.nonempty(properties.getDomain(), () -> "Local upload access domain is missing");
     }
 
     @Override

+ 5 - 5
framework-upload/src/main/java/com/chelvc/framework/upload/support/TencentUploadHandler.java

@@ -3,9 +3,9 @@ package com.chelvc.framework.upload.support;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Objects;
 
 import com.chelvc.framework.base.config.HttpClientProperties;
+import com.chelvc.framework.common.util.AssertUtils;
 import com.chelvc.framework.common.util.FileUtils;
 import com.chelvc.framework.common.util.StringUtils;
 import com.chelvc.framework.upload.UploadHandler;
@@ -30,8 +30,8 @@ public class TencentUploadHandler implements UploadHandler {
     private final COSClient client;
 
     public TencentUploadHandler(@NonNull UploadProperties.Client properties, @NonNull HttpClientProperties httpClient) {
-        this.path = Objects.requireNonNull(properties.getPath());
-        this.region = Objects.requireNonNull(properties.getRegion());
+        this.path = AssertUtils.nonempty(properties.getPath(), () -> "Tencent upload path is missing");
+        this.region = AssertUtils.nonempty(properties.getRegion(), () -> "Tencent upload region is missing");
 
         // 构建客户端配置
         ClientConfig config = new ClientConfig();
@@ -43,8 +43,8 @@ public class TencentUploadHandler implements UploadHandler {
         config.setConnectionRequestTimeout(httpClient.getConnectionRequestTimeout());
 
         // 初始化客户端实例
-        String id = Objects.requireNonNull(properties.getId());
-        String secret = Objects.requireNonNull(properties.getSecret());
+        String id = AssertUtils.nonempty(properties.getId(), () -> "Tencent upload id is missing");
+        String secret = AssertUtils.nonempty(properties.getSecret(), () -> "Tencent upload secret is missing");
         this.client = new COSClient(new BasicCOSCredentials(id, secret), config);
     }
 

+ 5 - 4
framework-wechat/src/main/java/com/chelvc/framework/wechat/DefaultWechatPaymentHandler.java

@@ -6,6 +6,7 @@ import java.util.Objects;
 
 import com.chelvc.framework.base.context.ApplicationContextHolder;
 import com.chelvc.framework.base.context.RestContextHolder;
+import com.chelvc.framework.common.util.AssertUtils;
 import com.chelvc.framework.common.util.DecimalUtils;
 import com.chelvc.framework.common.util.HostUtils;
 import com.chelvc.framework.common.util.ObjectUtils;
@@ -76,8 +77,8 @@ public class DefaultWechatPaymentHandler implements com.chelvc.framework.wechat.
      * @return 支付参数键/值对
      */
     private Map<String, String> buildPaymentParameter(WechatProperties.Payment payment, WechatPayRequest request) {
-        String mchid = Objects.requireNonNull(payment.getMchid());
-        String callback = Objects.requireNonNull(payment.getCallback());
+        String mchid = AssertUtils.nonempty(payment.getMchid(), () -> "Payment mchid is missing");
+        String callback = AssertUtils.nonempty(payment.getCallback(), () -> "Payment callback is missing");
         Map<String, String> parameters = Maps.newHashMap();
         parameters.put("appid", payment.getAppid());
         parameters.put("mch_id", mchid);
@@ -129,10 +130,10 @@ public class DefaultWechatPaymentHandler implements com.chelvc.framework.wechat.
 
         if (payment.getMode() == PayMode.MWEB) {
             // 如果是H5支付则需要指定scene_info,场景信息
-            parameters.put("scene_info", Objects.requireNonNull(request.getScene()));
+            parameters.put("scene_info", AssertUtils.nonempty(request.getScene(), () -> "Payment scene is missing"));
         } else if (payment.getMode() == PayMode.JSAPI) {
             // 如果是小程序支付则需要指定openid
-            parameters.put("openid", Objects.requireNonNull(request.getOpenid()));
+            parameters.put("openid", AssertUtils.nonempty(request.getOpenid(), () -> "Payment openid is missing"));
         }
 
         // 请求参数签名

+ 1 - 1
framework-wechat/src/main/java/com/chelvc/framework/wechat/DefaultWechatPublicHandler.java

@@ -82,7 +82,7 @@ public class DefaultWechatPublicHandler implements WechatPublicHandler {
 
     @Override
     public String decrypt(@NonNull String ciphertext) {
-        String secret = AssertUtils.nonempty(this.properties.getKey(), () -> "Secret is missing");
+        String secret = AssertUtils.nonempty(this.properties.getKey(), () -> "Wechat secret is missing");
         return WechatContextHolder.decrypt(ciphertext, secret);
     }