Kaynağa Gözat

update 优化

ct 20 saat önce
ebeveyn
işleme
3a9afb66a2

+ 30 - 4
fs-common/src/main/java/com/fs/common/config/CorsSupport.java

@@ -3,28 +3,48 @@ package com.fs.common.config;
 import org.springframework.util.StringUtils;
 import org.springframework.web.cors.CorsConfiguration;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * CORS 白名单(Spring Boot 2.2 无 setAllowedOriginPatterns,使用显式 Origin 列表)。
  * 通过环境变量 CORS_ALLOWED_ORIGINS 配置,逗号分隔;未配置时使用内置业务域名。
+ * <p>
+ * 注意:浏览器访问 http://localhost/ 时 Origin 为 {@code http://localhost}(无端口),
+ * 与 {@code http://localhost:80} 不同;漏配会导致 CorsFilter 直接 403。
  */
 public final class CorsSupport {
 
     private static final List<String> DEFAULT_ORIGINS = Arrays.asList(
+            // 金牛明医
+            "https://admin.jnmyunl.com",
+            "https://company.jnmyunl.com",
+            "https://doctor.jnmyunl.com",
+            // 通用业务域
             "https://admin.cdwjyyh.com",
             "https://company.cdwjyyh.com",
             "https://doctor.cdwjyyh.com",
             "https://h5.cdwjyyh.com",
+            // 本地:无端口(默认 80/443)与常见开发端口
+            "http://localhost",
+            "http://127.0.0.1",
             "http://localhost:80",
+            "http://localhost:81",
+            "http://localhost:1024",
             "http://localhost:8080",
             "http://localhost:8081",
-            "http://localhost:1024",
+            "http://localhost:9527",
+            "http://localhost:9528",
             "http://127.0.0.1:80",
+            "http://127.0.0.1:81",
+            "http://127.0.0.1:1024",
             "http://127.0.0.1:8080",
             "http://127.0.0.1:8081",
-            "http://127.0.0.1:1024"
+            "http://127.0.0.1:9527",
+            "http://127.0.0.1:9528"
     );
 
     private CorsSupport() {
@@ -38,14 +58,20 @@ public final class CorsSupport {
         }
         config.addAllowedHeader("*");
         config.addAllowedMethod("*");
+        config.setMaxAge(3600L);
         return config;
     }
 
     public static List<String> resolveOrigins() {
+        Set<String> origins = new LinkedHashSet<>(DEFAULT_ORIGINS);
         String env = System.getenv("CORS_ALLOWED_ORIGINS");
         if (StringUtils.hasText(env)) {
-            return Arrays.asList(env.split("\\s*,\\s*"));
+            for (String o : env.split("\\s*,\\s*")) {
+                if (StringUtils.hasText(o)) {
+                    origins.add(o.trim());
+                }
+            }
         }
-        return DEFAULT_ORIGINS;
+        return new ArrayList<>(origins);
     }
 }

+ 21 - 0
fs-common/src/main/java/com/fs/common/core/redis/RedisCache.java

@@ -2,6 +2,8 @@ package com.fs.common.core.redis;
 
 import java.util.*;
 import java.util.concurrent.TimeUnit;
+
+import com.alibaba.fastjson2.JSON;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.BoundSetOperations;
 import org.springframework.data.redis.core.HashOperations;
@@ -82,6 +84,25 @@ public class RedisCache
         return operation.get(key);
     }
 
+    /**
+     * 按目标类型读取缓存(兼容关闭 Fastjson AutoType 后 Redis 返回 JSONObject 的情况)。
+     */
+    public <T> T getCacheObject(final String key, final Class<T> clazz)
+    {
+        Object value = redisTemplate.opsForValue().get(key);
+        if (value == null || clazz == null) {
+            return null;
+        }
+        if (clazz.isInstance(value)) {
+            return clazz.cast(value);
+        }
+        try {
+            return JSON.parseObject(JSON.toJSONString(value), clazz);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
     /**
      * 删除单个对象
      *

+ 23 - 4
fs-common/src/main/java/com/fs/common/utils/DictUtils.java

@@ -1,7 +1,10 @@
 package com.fs.common.utils;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+
+import com.alibaba.fastjson2.JSON;
 import com.fs.common.constant.Constants;
 import com.fs.common.core.domain.entity.SysDictData;
 import com.fs.common.core.redis.RedisCache;
@@ -39,12 +42,20 @@ public class DictUtils
     public static List<SysDictData> getDictCache(String key)
     {
         Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
-        if (StringUtils.isNotNull(cacheObj))
+        if (StringUtils.isNull(cacheObj))
+        {
+            return null;
+        }
+        // 关闭 Fastjson AutoType 后 Redis 常返回 JSONArray/JSONObject,需显式转成 SysDictData
+        try
+        {
+            List<SysDictData> dictDatas = JSON.parseArray(JSON.toJSONString(cacheObj), SysDictData.class);
+            return dictDatas == null ? Collections.emptyList() : dictDatas;
+        }
+        catch (Exception e)
         {
-            List<SysDictData> dictDatas = StringUtils.cast(cacheObj);
-            return dictDatas;
+            return null;
         }
-        return null;
     }
 
     /**
@@ -83,6 +94,10 @@ public class DictUtils
     {
         StringBuilder propertyString = new StringBuilder();
         List<SysDictData> datas = getDictCache(dictType);
+        if (StringUtils.isEmpty(datas))
+        {
+            return StringUtils.EMPTY;
+        }
 
         if (StringUtils.containsAny(separator, dictValue) && StringUtils.isNotEmpty(datas))
         {
@@ -123,6 +138,10 @@ public class DictUtils
     {
         StringBuilder propertyString = new StringBuilder();
         List<SysDictData> datas = getDictCache(dictType);
+        if (StringUtils.isEmpty(datas))
+        {
+            return StringUtils.EMPTY;
+        }
 
         if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas))
         {

+ 26 - 19
fs-common/src/main/java/com/fs/common/utils/file/FileUtils.java

@@ -140,8 +140,13 @@ public class FileUtils
      */
     public static boolean checkAllowDownload(String resource)
     {
-        // 禁止目录上跳级别
-        if (StringUtils.contains(resource, ".."))
+        if (StringUtils.isEmpty(resource))
+        {
+            return false;
+        }
+        // 禁止目录上跳(含编码形态)
+        String normalized = resource.replace('\\', '/');
+        if (normalized.contains("..") || normalized.contains("%2e%2e") || normalized.contains("%2E%2E"))
         {
             return false;
         }
@@ -152,29 +157,31 @@ public class FileUtils
             return false;
         }
 
-        // 限制必须在上传根目录之下(防路径穿越)
-        try
+        // 仅对「绝对路径 / 带目录」的资源做 profile 根目录校验。
+        // /common/download 传入的是下载目录下的纯文件名,getCanonicalFile 会落到 cwd,不能按绝对路径误拒。
+        File raw = new File(resource);
+        if (raw.isAbsolute() || normalized.contains("/"))
         {
-            String profile = FSConfig.getProfile();
-            if (StringUtils.isNotEmpty(profile) && StringUtils.isNotEmpty(resource))
+            try
             {
+                String profile = FSConfig.getProfile();
+                if (StringUtils.isEmpty(profile))
+                {
+                    return false;
+                }
                 File base = new File(profile).getCanonicalFile();
-                File target = new File(resource).getCanonicalFile();
-                // resource 可能是相对文件名或绝对路径
-                if (target.isAbsolute())
+                File target = raw.getCanonicalFile();
+                String basePath = base.getPath();
+                String targetPath = target.getPath();
+                if (!targetPath.startsWith(basePath + File.separator) && !targetPath.equals(basePath))
                 {
-                    String basePath = base.getPath();
-                    String targetPath = target.getPath();
-                    if (!targetPath.startsWith(basePath + File.separator) && !targetPath.equals(basePath))
-                    {
-                        return false;
-                    }
+                    return false;
                 }
             }
-        }
-        catch (Exception e)
-        {
-            return false;
+            catch (Exception e)
+            {
+                return false;
+            }
         }
 
         return true;

+ 3 - 2
fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java

@@ -99,8 +99,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                 // 过滤请求
                 .authorizeRequests()
-                // 对于登录login 注册register 验证码captchaImage 允许匿名访问(chat/upload 需登录)
-                .antMatchers("/login", "/register", "/captchaImage","/checkIsNeedCheck","/getWechatQrCode","/checkWechatScan","/callback").anonymous()
+                // 登录相关须 permitAll:浏览器若仍带旧 Token,anonymous() 会对已认证用户返回 403
+                .antMatchers("/login", "/register", "/captchaImage", "/checkIsNeedCheck",
+                        "/getWechatQrCode", "/checkWechatScan", "/callback").permitAll()
                 .antMatchers(
                         HttpMethod.GET,
                         "/",

+ 24 - 12
fs-company/src/main/java/com/fs/framework/service/TokenService.java

@@ -61,22 +61,34 @@ public class TokenService
         String token = getToken(request);
         if (StringUtils.isNotEmpty(token))
         {
-            Claims claims = parseToken(token);
-            // 解析对应的权限以及用户信息
-            String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
-            String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
-            return user;
+            try
+            {
+                Claims claims = parseToken(token);
+                // 解析对应的权限以及用户信息
+                String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
+                String userKey = getTokenKey(uuid);
+                return redisCache.getCacheObject(userKey, LoginUser.class);
+            }
+            catch (Exception e)
+            {
+                return null;
+            }
         }
         token=getUrlToken(request);
         if (StringUtils.isNotEmpty(token))
         {
-            Claims claims = parseToken(token);
-            // 解析对应的权限以及用户信息
-            String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
-            String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
-            return user;
+            try
+            {
+                Claims claims = parseToken(token);
+                // 解析对应的权限以及用户信息
+                String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
+                String userKey = getTokenKey(uuid);
+                return redisCache.getCacheObject(userKey, LoginUser.class);
+            }
+            catch (Exception e)
+            {
+                return null;
+            }
         }
 
         return null;

+ 2 - 2
fs-company/src/main/resources/application.yml

@@ -3,9 +3,9 @@ server:
 # Spring配置
 spring:
   profiles:
-    active: dev
+#    active: dev
 #    active: druid-jnsyj-test
-#    active: druid-jnmy-test
+    active: druid-jnmy-test
 #    active: druid-jzzx-test
 #    active: druid-hdt
 #    active: druid-bjzm-test

+ 2 - 1
fs-framework/src/main/java/com/fs/framework/config/SecurityConfig.java

@@ -97,7 +97,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 // 过滤请求
                 .authorizeRequests()
                 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
-                .antMatchers("/login", "/register", "/captchaImage","/getWechatQrCode","/checkWechatScan","/callback","/checkIsNeedCheck","/api/open/kntAiExpress").anonymous()
+                .antMatchers("/login", "/register", "/captchaImage", "/getWechatQrCode", "/checkWechatScan",
+                        "/callback", "/checkIsNeedCheck", "/api/open/kntAiExpress").permitAll()
                 .antMatchers("/app/common/test").anonymous()
                 .antMatchers("/ad/adDyApi/authorized").anonymous()
                 .antMatchers(

+ 1 - 1
fs-framework/src/main/java/com/fs/framework/web/service/TokenService.java

@@ -66,7 +66,7 @@ public class TokenService
                 // 解析对应的权限以及用户信息
                 String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
                 String userKey = getTokenKey(uuid);
-                LoginUser user = redisCache.getCacheObject(userKey);
+                LoginUser user = redisCache.getCacheObject(userKey, LoginUser.class);
                 return user;
             }
             catch (Exception e)

+ 2 - 2
fs-ipad-task/src/main/java/com/fs/framework/service/TokenService.java

@@ -65,7 +65,7 @@ public class TokenService
             // 解析对应的权限以及用户信息
             String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
             String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
+            LoginUser user = redisCache.getCacheObject(userKey, LoginUser.class);
             return user;
         }
         token=getUrlToken(request);
@@ -75,7 +75,7 @@ public class TokenService
             // 解析对应的权限以及用户信息
             String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
             String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
+            LoginUser user = redisCache.getCacheObject(userKey, LoginUser.class);
             return user;
         }
 

+ 3 - 3
fs-qw-api-msg/src/main/java/com/fs/framework/service/TokenService.java

@@ -65,7 +65,7 @@ public class TokenService
             // 解析对应的权限以及用户信息
             String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
             String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
+            LoginUser user = redisCache.getCacheObject(userKey, LoginUser.class);
             return user;
         }
         token=getUrlToken(request);
@@ -75,7 +75,7 @@ public class TokenService
             // 解析对应的权限以及用户信息
             String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
             String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
+            LoginUser user = redisCache.getCacheObject(userKey, LoginUser.class);
             return user;
         }
 
@@ -92,7 +92,7 @@ public class TokenService
         // 解析对应的权限以及用户信息
         String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
         String userKey = getTokenKey(uuid);
-        return redisCache.getCacheObject(userKey);
+        return redisCache.getCacheObject(userKey, LoginUser.class);
 
     }
 

+ 2 - 2
fs-qw-api/src/main/java/com/fs/framework/service/TokenService.java

@@ -65,7 +65,7 @@ public class TokenService
             // 解析对应的权限以及用户信息
             String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
             String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
+            LoginUser user = redisCache.getCacheObject(userKey, LoginUser.class);
             return user;
         }
         token=getUrlToken(request);
@@ -75,7 +75,7 @@ public class TokenService
             // 解析对应的权限以及用户信息
             String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
             String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
+            LoginUser user = redisCache.getCacheObject(userKey, LoginUser.class);
             return user;
         }
 

+ 2 - 2
fs-qw-task/src/main/java/com/fs/framework/service/TokenService.java

@@ -65,7 +65,7 @@ public class TokenService
             // 解析对应的权限以及用户信息
             String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
             String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
+            LoginUser user = redisCache.getCacheObject(userKey, LoginUser.class);
             return user;
         }
         token=getUrlToken(request);
@@ -75,7 +75,7 @@ public class TokenService
             // 解析对应的权限以及用户信息
             String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
             String userKey = getTokenKey(uuid);
-            LoginUser user = redisCache.getCacheObject(userKey);
+            LoginUser user = redisCache.getCacheObject(userKey, LoginUser.class);
             return user;
         }
 

+ 27 - 28
fs-service/src/main/resources/application-common.yml

@@ -14,12 +14,12 @@ fs:
   addressEnabled: false
   # 验证码类型 math 数组计算 char 字符验证
   captchaType: math
-#  jwt:
-#    # 加密秘钥
-#    secret: f4e2e52034348f86b67cde581c0f9eb5
-#    # token有效时长,7天,单位秒
-#    expire: 31536000
-#    header: AppToken
+  jwt:
+    # 加密秘钥
+    secret: f4e2e52034348f86b67cde581c0f9eb5
+    # token有效时长,7天,单位秒
+    expire: 31536000
+    header: AppToken
 # 开发环境配置
 server:
   servlet:
@@ -55,11 +55,11 @@ spring:
 
   # 文件上传
   servlet:
-     multipart:
-       # 单个文件大小
-       max-file-size:  3GB
-       # 设置总上传的文件大小
-       max-request-size:  3GB
+    multipart:
+      # 单个文件大小
+      max-file-size:  3GB
+      # 设置总上传的文件大小
+      max-request-size:  3GB
   # 服务模块
   devtools:
     restart:
@@ -69,12 +69,12 @@ spring:
 
 # token配置
 token:
-    # 令牌自定义标识
-    header: Authorization
-    # 令牌密钥已迁 scrm.env → TOKEN_SECRET
-    secret: ${TOKEN_SECRET:}
-    # 令牌有效期(默认30分钟)
-    expireTime: 720
+  # 令牌自定义标识
+  header: Authorization
+  # 令牌密钥
+  secret: abcdefghijklmnopqrstuvwxyz
+  # 令牌有效期(默认30分钟)
+  expireTime: 720
 mybatis-plus:
   # 搜索指定包别名
   typeAliasesPackage: com.fs.**.domain,com.fs.**.bo
@@ -102,12 +102,12 @@ mybatis-plus:
 
 # MyBatis配置
 mybatis:
-    # 搜索指定包别名
-    typeAliasesPackage: com.fs.**.domain
-    # 配置mapper的扫描,找到所有的mapper.xml映射文件
-    mapperLocations: classpath*:mapper/**/*Mapper.xml
-    # 加载全局的配置文件
-    configLocation: classpath:mybatis/mybatis-config.xml
+  # 搜索指定包别名
+  typeAliasesPackage: com.fs.**.domain
+  # 配置mapper的扫描,找到所有的mapper.xml映射文件
+  mapperLocations: classpath*:mapper/**/*Mapper.xml
+  # 加载全局的配置文件
+  configLocation: classpath:mybatis/mybatis-config.xml
 
 # PageHelper分页插件
 pagehelper:
@@ -144,11 +144,10 @@ wechat:
     base-url: https://api.weixin.qq.com
     upload-shipping-info: /wxa/sec/order/upload_shipping_info
 hsy:
-  # 密钥已迁 scrm.env → HSY_ACCESS_KEY / HSY_SECRET_KEY / HSY_ROLE_*
-  access_key: ${HSY_ACCESS_KEY:}
-  secret_key: ${HSY_SECRET_KEY:}
+  access_key: AKLTZTc4YTE4ZjI2OWViNDNjZGI2NjhiYTI5Njc5ZjA1Mzk
+  secret_key: WXpjelpUYzFOakF5TUdObE5EZGtNR0ZsWXpKaU1tTmtZakk1WXpObE4yRQ==
   region: cn-north-1
-  role_access_key: ${HSY_ROLE_ACCESS_KEY:}
-  role_secret_key: ${HSY_ROLE_SECRET_KEY:}
+  role_access_key: AKLTNmMwNjJkNDFhYTVjNDIzYzhhNzEyZmZmZTlmYzBhNGM
+  role_secret_key: T0RaaFl6UmhZV1V4WXpKbU5EWTBNMkZpT0RNNU9UY3daak0wTjJFd09XUQ==
   role_trn: trn:iam::2114522511:role/hylj
 

+ 2 - 2
fs-store/src/main/java/com/fs/framework/service/TokenService.java

@@ -75,7 +75,7 @@ public class TokenService
                 // 解析对应的权限以及用户信息
                 String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
                 String userKey = getTokenKey(uuid);
-                StoreLoginUser user = redisCache.getCacheObject(userKey);
+                StoreLoginUser user = redisCache.getCacheObject(userKey, StoreLoginUser.class);
                 return user;
             }
             catch (Exception e)
@@ -251,7 +251,7 @@ public class TokenService
                 // 解析对应的权限以及用户信息
                 String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
                 String userKey = getTokenKey(uuid);
-                StoreLoginUserScrm user = redisCache.getCacheObject(userKey);
+                StoreLoginUserScrm user = redisCache.getCacheObject(userKey, StoreLoginUserScrm.class);
                 return user;
             }
             catch (Exception e)

+ 3 - 3
fs-watch/src/main/java/com/fs/framework/service/TokenService.java

@@ -72,11 +72,11 @@ public class TokenService
             if ("admin".equals(type)){
                 uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
                 userKey = getAdminTokenKey(uuid);
-                return redisCache.getCacheObject(userKey);
+                return redisCache.getCacheObject(userKey, LoginUser.class);
             } else if ("company".equals(type)){
                 uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
                 userKey = getTokenKey(uuid);
-                return redisCache.getCacheObject(userKey);
+                return redisCache.getCacheObject(userKey, com.fs.framework.security.LoginUser.class);
 
             }
 
@@ -89,7 +89,7 @@ public class TokenService
             // 解析对应的权限以及用户信息
             String uuid = (String) claims.get(Constants.COMPANY_LOGIN_USER_KEY);
             String userKey = getTokenKey(uuid);
-            LoginCompanyUser user = redisCache.getCacheObject(userKey);
+            LoginCompanyUser user = redisCache.getCacheObject(userKey, LoginCompanyUser.class);
             return user;
         }