Sfoglia il codice sorgente

新增获取安全的环境变量值工具方法;优化短信验证码逻辑;

woody 1 anno fa
parent
commit
2df2cadbf7

+ 147 - 5
framework-base/src/main/java/com/chelvc/framework/base/context/ApplicationContextHolder.java

@@ -12,7 +12,9 @@ import java.util.stream.Collectors;
 import com.beust.jcommander.internal.Sets;
 import com.beust.jcommander.internal.Sets;
 import com.chelvc.framework.base.util.ObjectUtils;
 import com.chelvc.framework.base.util.ObjectUtils;
 import com.chelvc.framework.base.util.StringUtils;
 import com.chelvc.framework.base.util.StringUtils;
+import com.fasterxml.jackson.core.type.TypeReference;
 import lombok.NonNull;
 import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
 import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
@@ -33,6 +35,7 @@ import org.springframework.stereotype.Component;
  * @author Woody
  * @author Woody
  * @date 2023/4/5
  * @date 2023/4/5
  */
  */
+@Slf4j
 @Component
 @Component
 public class ApplicationContextHolder implements ApplicationContextAware {
 public class ApplicationContextHolder implements ApplicationContextAware {
     /**
     /**
@@ -51,6 +54,11 @@ public class ApplicationContextHolder implements ApplicationContextAware {
      */
      */
     private static ApplicationContext APPLICATION_CONTEXT;
     private static ApplicationContext APPLICATION_CONTEXT;
 
 
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        APPLICATION_CONTEXT = applicationContext;
+    }
+
     /**
     /**
      * 获取应用上下文对象
      * 获取应用上下文对象
      *
      *
@@ -60,11 +68,6 @@ public class ApplicationContextHolder implements ApplicationContextAware {
         return Objects.requireNonNull(APPLICATION_CONTEXT, "Application context has not been initialized");
         return Objects.requireNonNull(APPLICATION_CONTEXT, "Application context has not been initialized");
     }
     }
 
 
-    @Override
-    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
-        APPLICATION_CONTEXT = applicationContext;
-    }
-
     /**
     /**
      * 获取应用环境变量信息
      * 获取应用环境变量信息
      *
      *
@@ -84,6 +87,21 @@ public class ApplicationContextHolder implements ApplicationContextAware {
         return getEnvironment().getProperty(key);
         return getEnvironment().getProperty(key);
     }
     }
 
 
+    /**
+     * 获取安全的环境变量值
+     *
+     * @param key 变量名称
+     * @return 变量值
+     */
+    public static String getSafeProperty(String key) {
+        try {
+            return getProperty(key);
+        } catch (Exception e) {
+            log.warn("Application property get failed: {}, {}", key, e.getMessage());
+        }
+        return null;
+    }
+
     /**
     /**
      * 获取环境变量值
      * 获取环境变量值
      *
      *
@@ -95,6 +113,22 @@ public class ApplicationContextHolder implements ApplicationContextAware {
         return getEnvironment().getProperty(key, defaultValue);
         return getEnvironment().getProperty(key, defaultValue);
     }
     }
 
 
+    /**
+     * 获取安全的环境变量值
+     *
+     * @param key          变量名称
+     * @param defaultValue 默认值
+     * @return 变量值
+     */
+    public static String getSafeProperty(String key, String defaultValue) {
+        try {
+            return getProperty(key, defaultValue);
+        } catch (Exception e) {
+            log.warn("Application property get failed: {}, {}", key, e.getMessage());
+        }
+        return defaultValue;
+    }
+
     /**
     /**
      * 获取环境变量值
      * 获取环境变量值
      *
      *
@@ -107,6 +141,52 @@ public class ApplicationContextHolder implements ApplicationContextAware {
         return getEnvironment().getProperty(key, targetType);
         return getEnvironment().getProperty(key, targetType);
     }
     }
 
 
+    /**
+     * 获取安全的环境变量值
+     *
+     * @param key        变量名称
+     * @param targetType 变量值类型
+     * @param <T>        变量值类型
+     * @return 变量值
+     */
+    public static <T> T getSafeProperty(String key, Class<T> targetType) {
+        try {
+            return getProperty(key, targetType);
+        } catch (Exception e) {
+            log.warn("Application property get failed: {}, {}", key, e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * 获取环境变量值
+     *
+     * @param key        变量名称
+     * @param targetType 变量值类型
+     * @param <T>        变量值类型
+     * @return 变量值
+     */
+    public static <T> T getProperty(String key, TypeReference<T> targetType) {
+        return JacksonContextHolder.deserialize(getProperty(key), targetType);
+    }
+
+    /**
+     * 获取安全的环境变量值
+     *
+     * @param key        变量名称
+     * @param targetType 变量值类型
+     * @param <T>        变量值类型
+     * @return 变量值
+     */
+    public static <T> T getSafeProperty(String key, TypeReference<T> targetType) {
+        try {
+            return getProperty(key, targetType);
+        } catch (Exception e) {
+            log.warn("Application property get failed: {}, {}", key, e.getMessage());
+        }
+        return null;
+    }
+
     /**
     /**
      * 获取环境变量值
      * 获取环境变量值
      *
      *
@@ -120,6 +200,55 @@ public class ApplicationContextHolder implements ApplicationContextAware {
         return getEnvironment().getProperty(key, targetType, defaultValue);
         return getEnvironment().getProperty(key, targetType, defaultValue);
     }
     }
 
 
+    /**
+     * 获取安全的环境变量值
+     *
+     * @param key          变量名称
+     * @param targetType   变量值类型
+     * @param defaultValue 默认值
+     * @param <T>          变量值类型
+     * @return 环境变量值
+     */
+    public static <T> T getSafeProperty(String key, Class<T> targetType, T defaultValue) {
+        try {
+            return getProperty(key, targetType, defaultValue);
+        } catch (Exception e) {
+            log.warn("Application property get failed: {}, {}", key, e.getMessage());
+        }
+        return defaultValue;
+    }
+
+    /**
+     * 获取环境变量值
+     *
+     * @param key          变量名称
+     * @param targetType   变量值类型
+     * @param defaultValue 默认值
+     * @param <T>          变量值类型
+     * @return 环境变量值
+     */
+    public static <T> T getProperty(String key, TypeReference<T> targetType, T defaultValue) {
+        return ObjectUtils.ifNull(getProperty(key, targetType), defaultValue);
+    }
+
+    /**
+     * 获取安全的环境变量值
+     *
+     * @param key          变量名称
+     * @param targetType   变量值类型
+     * @param defaultValue 默认值
+     * @param <T>          变量值类型
+     * @return 环境变量值
+     */
+    public static <T> T getSafeProperty(String key, TypeReference<T> targetType, T defaultValue) {
+        try {
+            return getProperty(key, targetType, defaultValue);
+        } catch (Exception e) {
+            log.warn("Application property get failed: {}, {}", key, e.getMessage());
+        }
+        return defaultValue;
+    }
+
     /**
     /**
      * 获取必须的环境变量
      * 获取必须的环境变量
      *
      *
@@ -144,6 +273,19 @@ public class ApplicationContextHolder implements ApplicationContextAware {
         return getEnvironment().getRequiredProperty(key, targetType);
         return getEnvironment().getRequiredProperty(key, targetType);
     }
     }
 
 
+    /**
+     * 获取必须的环境变量
+     *
+     * @param key        变量名称
+     * @param targetType 变量值类型
+     * @param <T>        变量值类型
+     * @return 变量值
+     * @throws IllegalStateException 状态异常
+     */
+    public static <T> T getRequiredProperty(String key, TypeReference<T> targetType) throws IllegalStateException {
+        return JacksonContextHolder.deserialize(getRequiredProperty(key), targetType);
+    }
+
     /**
     /**
      * 获取对象实例
      * 获取对象实例
      *
      *

+ 1 - 1
framework-base/src/main/java/com/chelvc/framework/base/context/SessionContextHolder.java

@@ -708,7 +708,7 @@ public class SessionContextHolder implements ServletRequestListener {
         if (session == null) {
         if (session == null) {
             return false;
             return false;
         }
         }
-        int sequence = ApplicationContextHolder.getProperty("platform.test.sequence", int.class, 0);
+        int sequence = ApplicationContextHolder.getSafeProperty("platform.test.sequence", int.class, 0);
         return (platform == null || platform == session.getPlatform())
         return (platform == null || platform == session.getPlatform())
                 && (terminal == null || terminal == session.getTerminal())
                 && (terminal == null || terminal == session.getTerminal())
                 && ObjectUtils.ifNull(session.getSequence(), 0) > sequence;
                 && ObjectUtils.ifNull(session.getSequence(), 0) > sequence;

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

@@ -91,7 +91,7 @@ public class RequestLoggingInterceptor implements SmartInitializingSingleton {
 
 
                 // 根据对象名称获取日志级别
                 // 根据对象名称获取日志级别
                 String key = "platform.logging." + logger.getName();
                 String key = "platform.logging." + logger.getName();
-                Set<?> levels = ApplicationContextHolder.getProperty(key, Set.class);
+                Set<?> levels = ApplicationContextHolder.getSafeProperty(key, Set.class);
                 if (CollectionUtils.isEmpty(levels)
                 if (CollectionUtils.isEmpty(levels)
                         || levels.stream().map(Object::toString).noneMatch(level.levelStr::equalsIgnoreCase)) {
                         || levels.stream().map(Object::toString).noneMatch(level.levelStr::equalsIgnoreCase)) {
                     return FilterReply.NEUTRAL;
                     return FilterReply.NEUTRAL;

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

@@ -408,7 +408,7 @@ public class SecurityContextHolder implements ApplicationContextAware, ServletRe
      * @return 角色/权限映射表
      * @return 角色/权限映射表
      */
      */
     public static Map<String, Set<String>> getContextPermissions() {
     public static Map<String, Set<String>> getContextPermissions() {
-        String permission = ApplicationContextHolder.getProperty(PERMISSION_PROPERTY);
+        String permission = ApplicationContextHolder.getSafeProperty(PERMISSION_PROPERTY);
         return StringUtils.isEmpty(permission) ? Collections.emptyMap() :
         return StringUtils.isEmpty(permission) ? Collections.emptyMap() :
                 JacksonContextHolder.deserialize(permission, PERMISSION_TYPE_REFERENCE);
                 JacksonContextHolder.deserialize(permission, PERMISSION_TYPE_REFERENCE);
     }
     }

+ 17 - 39
framework-sms/src/main/java/com/chelvc/framework/sms/support/DefaultCaptchaSmsHandler.java

@@ -8,8 +8,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.function.Consumer;
 
 
 import com.chelvc.framework.base.context.ApplicationContextHolder;
 import com.chelvc.framework.base.context.ApplicationContextHolder;
-import com.chelvc.framework.base.context.JacksonContextHolder;
-import com.chelvc.framework.base.context.SessionContextHolder;
 import com.chelvc.framework.base.exception.ResourceUnavailableException;
 import com.chelvc.framework.base.exception.ResourceUnavailableException;
 import com.chelvc.framework.base.util.StringUtils;
 import com.chelvc.framework.base.util.StringUtils;
 import com.chelvc.framework.redis.util.RedisUtils;
 import com.chelvc.framework.redis.util.RedisUtils;
@@ -59,38 +57,12 @@ public class DefaultCaptchaSmsHandler implements CaptchaSmsHandler {
         return "sms:token:" + mobile;
         return "sms:token:" + mobile;
     }
     }
 
 
-    /**
-     * 生成验证码
-     *
-     * @param mobile  手机号
-     * @param testing 是否是测试模式
-     * @return 验证码
-     */
-    private String generateCaptcha(String mobile, boolean testing) {
-        if (testing) {
-            List<Captcha> testes = JacksonContextHolder.deserialize(
-                    ApplicationContextHolder.getProperty("platform.auth.sms.test"), CAPTCHA_REFERENCE
-            );
-            if (!CollectionUtils.isEmpty(testes)) {
-                String code = testes.stream().filter(test -> Objects.equals(test.getMobile(), mobile))
-                        .findAny().map(Captcha::getCode).orElse(null);
-                if (StringUtils.nonEmpty(code)) {
-                    return code;
-                }
-            }
-        }
-        return String.valueOf(ThreadLocalRandom.current().nextInt(100000, 1000000));
-    }
-
     @Override
     @Override
     public SmsSession send(@NonNull String mobile) {
     public SmsSession send(@NonNull String mobile) {
-        boolean testing = SessionContextHolder.isTesting();
-        String code = this.generateCaptcha(mobile, testing);
+        String code = String.valueOf(ThreadLocalRandom.current().nextInt(100000, 1000000));
         Duration duration = Duration.ofSeconds(this.properties.getInterval());
         Duration duration = Duration.ofSeconds(this.properties.getInterval());
         return RedisUtils.tryLockAround("sms:interval:" + mobile, duration, () -> {
         return RedisUtils.tryLockAround("sms:interval:" + mobile, duration, () -> {
-            if (!testing) {
-                this.templateSmsHandler.sendCaptcha(mobile, this.properties.getTemplate(), code);
-            }
+            this.templateSmsHandler.sendCaptcha(mobile, this.properties.getTemplate(), code);
             String key = this.key(mobile), token = StringUtils.uuid();
             String key = this.key(mobile), token = StringUtils.uuid();
             Captcha captcha = Captcha.builder().token(token).code(code).mobile(mobile).build();
             Captcha captcha = Captcha.builder().token(token).code(code).mobile(mobile).build();
             this.redisTemplate.opsForValue().set(key, captcha, this.properties.getExpiration(), TimeUnit.SECONDS);
             this.redisTemplate.opsForValue().set(key, captcha, this.properties.getExpiration(), TimeUnit.SECONDS);
@@ -101,12 +73,21 @@ public class DefaultCaptchaSmsHandler implements CaptchaSmsHandler {
     }
     }
 
 
     @Override
     @Override
-    public Captcha getCaptcha(String mobile) {
-        return StringUtils.isEmpty(mobile) ? null : (Captcha) this.redisTemplate.opsForValue().get(this.key(mobile));
+    public Captcha getCaptcha(@NonNull String mobile) {
+        // 如果目标手机号属于测试手机号,则直接返回配置的验证码信息,否则获取真实的验证码
+        List<Captcha> testes = ApplicationContextHolder.getSafeProperty("platform.sms.captcha.test", CAPTCHA_REFERENCE);
+        if (!CollectionUtils.isEmpty(testes)) {
+            Captcha captcha = testes.stream().filter(test -> Objects.equals(test.getMobile(), mobile))
+                    .findFirst().orElse(null);
+            if (captcha != null) {
+                return captcha;
+            }
+        }
+        return (Captcha) this.redisTemplate.opsForValue().get(this.key(mobile));
     }
     }
 
 
     @Override
     @Override
-    public void using(String mobile, @NonNull Consumer<Captcha> consumer) {
+    public void using(@NonNull String mobile, @NonNull Consumer<Captcha> consumer) {
         Captcha captcha = this.getCaptcha(mobile);
         Captcha captcha = this.getCaptcha(mobile);
         consumer.accept(captcha);
         consumer.accept(captcha);
         if (captcha != null) {
         if (captcha != null) {
@@ -115,17 +96,14 @@ public class DefaultCaptchaSmsHandler implements CaptchaSmsHandler {
     }
     }
 
 
     @Override
     @Override
-    public boolean check(String token, String mobile, String code) {
-        if (StringUtils.isEmpty(token) || StringUtils.isEmpty(mobile) || StringUtils.isEmpty(code)) {
-            return false;
-        }
+    public boolean check(String token, @NonNull String mobile, @NonNull String code) {
         Captcha captcha = this.getCaptcha(mobile);
         Captcha captcha = this.getCaptcha(mobile);
-        return captcha != null && Objects.equals(token, captcha.getToken())
+        return captcha != null && (StringUtils.isEmpty(captcha.getToken()) || Objects.equals(token, captcha.getToken()))
                 && Objects.equals(mobile, captcha.getMobile()) && Objects.equals(code, captcha.getCode());
                 && Objects.equals(mobile, captcha.getMobile()) && Objects.equals(code, captcha.getCode());
     }
     }
 
 
     @Override
     @Override
-    public boolean validate(String token, String mobile, String code) {
+    public boolean validate(String token, @NonNull String mobile, @NonNull String code) {
         boolean available = this.check(token, mobile, code);
         boolean available = this.check(token, mobile, code);
         if (available) {
         if (available) {
             this.redisTemplate.delete(this.key(mobile));
             this.redisTemplate.delete(this.key(mobile));