Browse Source

!270 发布 2.6.2 版本 依赖升级

* 🦁🦁🦁发布 2.6.2 版本 依赖升级
* update springboot 3.5.14 => 3.5.15
* update 优化 防止工作流保存被xss过滤
* update README.md
* add 新增 赞助商
* fix 修复 mvc网关与flux网关 异常行为返回内容不同问题
* fix 修复 多次驳回无法锁定审批人问题
* update 优化 findInSet 方法 增加参数校验防止注入
* Revert "fix 修复 dubbo 元数据实现类 json工具使用错误问题"
* fix 修复 dubbo 元数据实现类 json工具使用错误问题
* update 优化 findInSet 方法 增加参数校验防止注入
* fix 修复 gateway设置默认请求头无法覆盖问题
* fix 修复 gateway设置默认请求头无法覆盖问题
* fix 修复 前端输入性CVE漏洞 禁止使用代码生成到本地路径
疯狂的狮子Li 1 month ago
parent
commit
ce0dd0d941
28 changed files with 124 additions and 156 deletions
  1. 1 1
      .run/ruoyi-auth.run.xml
  2. 1 1
      .run/ruoyi-gateway.run.xml
  3. 1 1
      .run/ruoyi-gen.run.xml
  4. 1 1
      .run/ruoyi-job.run.xml
  5. 1 1
      .run/ruoyi-monitor.run.xml
  6. 1 1
      .run/ruoyi-nacos.run.xml
  7. 1 1
      .run/ruoyi-resource.run.xml
  8. 1 1
      .run/ruoyi-seata-server.run.xml
  9. 1 1
      .run/ruoyi-snailjob-server.run.xml
  10. 1 1
      .run/ruoyi-system.run.xml
  11. 1 1
      .run/ruoyi-workflow.run.xml
  12. 3 3
      README.md
  13. 3 3
      pom.xml
  14. 1 1
      ruoyi-api/ruoyi-api-bom/pom.xml
  15. 1 1
      ruoyi-common/ruoyi-common-alibaba-bom/pom.xml
  16. 1 1
      ruoyi-common/ruoyi-common-bom/pom.xml
  17. 15 4
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java
  18. 30 15
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java
  19. 6 0
      ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfiguration.java
  20. 32 29
      ruoyi-gateway-mvc/src/main/java/org/dromara/gateway/filter/AuthFilter.java
  21. 0 2
      ruoyi-gateway/src/main/java/org/dromara/gateway/filter/AuthFilter.java
  22. 0 13
      ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java
  23. 2 2
      ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTable.java
  24. 2 50
      ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java
  25. 0 7
      ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java
  26. 5 3
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java
  27. 1 0
      script/config/nacos/application-common.yml
  28. 11 11
      script/docker/docker-compose.yml

+ 1 - 1
.run/ruoyi-auth.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-auth" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-auth:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-auth:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-auth/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-gateway.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-gateway" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-gateway:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-gateway:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-gateway/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-gen.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-gen" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-gen:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-gen:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-modules/ruoyi-gen/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-job.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-job" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-job:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-job:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-modules/ruoyi-job/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-monitor.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-monitor" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-monitor:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-monitor:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-visual/ruoyi-monitor/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-nacos.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-nacos" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-nacos:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-nacos:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-visual/ruoyi-nacos/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-resource.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-resource" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-resource:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-resource:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-modules/ruoyi-resource/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-seata-server.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-seata-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-seata-server:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-seata-server:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-visual/ruoyi-seata-server/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-snailjob-server.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-visual/ruoyi-snailjob-server/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-system.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-system" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-system:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-system:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-modules/ruoyi-system/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-workflow.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-workflow" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-workflow:2.6.1" />
+        <option name="imageTag" value="ruoyi/ruoyi-workflow:2.6.2" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-modules/ruoyi-workflow/Dockerfile" />
       </settings>

+ 3 - 3
README.md

@@ -5,11 +5,11 @@
 ## 平台简介
 
 [![码云Gitee](https://gitee.com/dromara/RuoYi-Cloud-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Cloud-Plus)
-[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Cloud-Plus.svg?label=Github%20Stars)](https://github.com/dromara/RuoYi-Cloud-Plus)
+[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Cloud-Plus?style=social&label=Github%20Stars)](https://github.com/dromara/RuoYi-Cloud-Plus)
 [![Star](https://gitcode.com/dromara/RuoYi-Cloud-Plus/star/badge.svg)](https://gitcode.com/dromara/RuoYi-Cloud-Plus)
 [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Cloud-Plus/blob/2.X/LICENSE)
 <br>
-[![RuoYi-Cloud-Plus](https://img.shields.io/badge/RuoYi_Cloud_Plus-2.6.1-success.svg)](https://gitee.com/dromara/RuoYi-Cloud-Plus)
+[![RuoYi-Cloud-Plus](https://img.shields.io/badge/RuoYi_Cloud_Plus-2.6.2-success.svg)](https://gitee.com/dromara/RuoYi-Cloud-Plus)
 [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.5-blue.svg)]()
 [![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
 [![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()
@@ -33,11 +33,11 @@
 MaxKey 业界领先单点登录产品 - https://gitee.com/dromara/MaxKey <br>
 CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow <br>
 数舵科技 软件定制开发APP小程序等 - https://www.shuduokeji.com/ <br>
-引迈信息 软件开发平台 - https://www.jnpfsoft.com/index.html?from=plus-doc <br>
 Mall4J 高质量Java商城系统 - https://www.mall4j.com/cn/?statId=11 <br>
 aizuda flowlong 工作流 - https://gitee.com/aizuda/flowlong <br>
 Ruoyi-Plus-Uniapp - https://ruoyi.plus <br>
 Topiam IAM/IDaaS身份管理平台 - https://www.topiam.cn/ <br>
+稳定低价的大模型中转站 - https://aicodelink.top/register?aff=pHeG <br>
 
 [如何成为赞助商 加群联系作者详谈 每日PV2500-3000 IP1700-2500](https://plus-doc.dromara.org/#/common/add_group)
 

+ 3 - 3
pom.xml

@@ -13,12 +13,12 @@
     <description>Dromara RuoYi-Cloud-Plus微服务系统</description>
 
     <properties>
-        <revision>2.6.1</revision>
+        <revision>2.6.2</revision>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>17</java.version>
-        <spring-boot.version>3.5.14</spring-boot.version>
-        <spring-cloud.version>2025.0.2</spring-cloud.version>
+        <spring-boot.version>3.5.15</spring-boot.version>
+        <spring-cloud.version>2025.0.3</spring-cloud.version>
         <spring-boot-admin.version>3.5.8</spring-boot-admin.version>
         <mybatis.version>3.5.19</mybatis.version>
         <mybatis-plus.version>3.5.16</mybatis-plus.version>

+ 1 - 1
ruoyi-api/ruoyi-api-bom/pom.xml

@@ -15,7 +15,7 @@
     </description>
 
     <properties>
-        <revision>2.6.1</revision>
+        <revision>2.6.2</revision>
     </properties>
 
     <dependencyManagement>

+ 1 - 1
ruoyi-common/ruoyi-common-alibaba-bom/pom.xml

@@ -14,7 +14,7 @@
     </description>
 
     <properties>
-        <revision>2.6.1</revision>
+        <revision>2.6.2</revision>
         <spring-cloud-alibaba.version>2025.0.0.0</spring-cloud-alibaba.version>
         <seata.version>2.6.0</seata.version>
         <nacos.client.version>2.5.1</nacos.client.version>

+ 1 - 1
ruoyi-common/ruoyi-common-bom/pom.xml

@@ -14,7 +14,7 @@
     </description>
 
     <properties>
-        <revision>2.6.1</revision>
+        <revision>2.6.2</revision>
     </properties>
 
     <dependencyManagement>

+ 15 - 4
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java

@@ -1,5 +1,6 @@
 package org.dromara.common.core.utils.sql;
 
+import cn.hutool.core.exceptions.UtilException;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.dromara.common.core.utils.StringUtils;
@@ -7,7 +8,7 @@ import org.dromara.common.core.utils.StringUtils;
 /**
  * sql操作工具类
  *
- * @author ruoyi
+ * @author Lion Li
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class SqlUtil {
@@ -15,7 +16,7 @@ public class SqlUtil {
     /**
      * 定义常用的 sql关键字
      */
-    public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
+    public static final String SQL_REGEX = "\u000B|%0A|and |extractvalue|updatexml|sleep|information_schema|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
 
     /**
      * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
@@ -46,11 +47,21 @@ public class SqlUtil {
         if (StringUtils.isEmpty(value)) {
             return;
         }
+
+        // ==================== 核心增强:自动转义单引号 ====================
+        // 不抛异常、不破坏业务、不改变原方法行为、自动防注入
+        if (value.contains("'")) {
+            throw new UtilException("请求参数包含非法字符【'】,已禁止执行");
+        }
+
+        // ==================== 原有逻辑不变 ====================
+        String normalizedValue = value.replaceAll("\\p{Z}|\\s", "");
         String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
         for (String sqlKeyword : sqlKeywords) {
-            if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) {
-                throw new IllegalArgumentException("参数存在SQL注入风险");
+            if (StringUtils.indexOf(normalizedValue, sqlKeyword) > -1) {
+                throw new UtilException("请求参数包含敏感关键词'" + sqlKeyword + "',可能存在安全风险");
             }
         }
     }
+
 }

+ 30 - 15
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java

@@ -2,10 +2,12 @@ package org.dromara.common.mybatis.helper;
 
 import cn.hutool.core.convert.Convert;
 import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.sql.SqlUtil;
 import org.dromara.common.mybatis.enums.DataBaseType;
 
 import javax.sql.DataSource;
@@ -14,6 +16,8 @@ import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * 数据库助手
@@ -24,6 +28,7 @@ import java.util.List;
 public class DataBaseHelper {
 
     private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class);
+    private static final Map<String, DataBaseType> DB_TYPE_CACHE = new ConcurrentHashMap<>();
 
     /**
      * 获取当前数据源对应的数据库类型
@@ -37,13 +42,17 @@ public class DataBaseHelper {
      */
     public static DataBaseType getDataBaseType() {
         DataSource dataSource = DS.determineDataSource();
-        try (Connection conn = dataSource.getConnection()) {
-            DatabaseMetaData metaData = conn.getMetaData();
-            String databaseProductName = metaData.getDatabaseProductName();
-            return DataBaseType.find(databaseProductName);
-        } catch (SQLException e) {
-            throw new RuntimeException("获取数据库类型失败", e);
-        }
+        String dsKey = DynamicDataSourceContextHolder.peek();
+        final String key = dsKey != null ? dsKey : "primary";
+        return DB_TYPE_CACHE.computeIfAbsent(key, k -> {
+            try (Connection conn = dataSource.getConnection()) {
+                DatabaseMetaData metaData = conn.getMetaData();
+                String databaseProductName = metaData.getDatabaseProductName();
+                return DataBaseType.find(databaseProductName);
+            } catch (SQLException e) {
+                throw new RuntimeException("获取数据库类型失败", e);
+            }
+        });
     }
 
     /**
@@ -55,13 +64,15 @@ public class DataBaseHelper {
      */
     public static DataBaseType getDataBaseType(String dsName) {
         DataSource dataSource = DS.getDataSource(dsName);
-        try (Connection conn = dataSource.getConnection()) {
-            DatabaseMetaData metaData = conn.getMetaData();
-            String databaseProductName = metaData.getDatabaseProductName();
-            return DataBaseType.find(databaseProductName);
-        } catch (SQLException e) {
-            throw new RuntimeException("获取数据库类型失败", e);
-        }
+        return DB_TYPE_CACHE.computeIfAbsent(dsName, k -> {
+            try (Connection conn = dataSource.getConnection()) {
+                DatabaseMetaData metaData = conn.getMetaData();
+                String databaseProductName = metaData.getDatabaseProductName();
+                return DataBaseType.find(databaseProductName);
+            } catch (SQLException e) {
+                throw new RuntimeException("获取数据库类型失败", e);
+            }
+        });
     }
 
     /**
@@ -79,6 +90,8 @@ public class DataBaseHelper {
      */
     public static String findInSet(Object var1, String var2) {
         String var = Convert.toStr(var1);
+        SqlUtil.filterKeyword(var);
+        SqlUtil.filterKeyword(var2);
         return switch (getDataBaseType()) {
             // instr(',0,100,101,' , ',100,') <> 0
             case ORACLE -> "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var);
@@ -92,7 +105,9 @@ public class DataBaseHelper {
     }
 
     /**
-     * 获取当前加载的数据库名
+     * 获取当前注册的数据源名称列表。
+     *
+     * @return 数据源名称列表
      */
     public static List<String> getDataSourceNameList() {
         return new ArrayList<>(DS.getDataSources().keySet());

+ 6 - 0
ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfiguration.java

@@ -6,7 +6,10 @@ import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil;
 import cn.dev33.satoken.interceptor.SaInterceptor;
 import cn.dev33.satoken.same.SaSameUtil;
 import cn.dev33.satoken.util.SaResult;
+import cn.dev33.satoken.util.SaTokenConsts;
+import jakarta.servlet.http.HttpServletResponse;
 import org.dromara.common.core.constant.HttpStatus;
+import org.dromara.common.core.utils.ServletUtils;
 import org.dromara.common.core.utils.SpringUtils;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.context.annotation.Bean;
@@ -42,6 +45,9 @@ public class SecurityConfiguration implements WebMvcConfigurer {
                 if (SaManager.getConfig().getCheckSameToken()) {
                     SaSameUtil.checkCurrentRequestToken();
                 }
+                // 对响应体设置默认头 后续代码可以覆盖
+                HttpServletResponse response = ServletUtils.getResponse();
+                response.setContentType(SaTokenConsts.CONTENT_TYPE_APPLICATION_JSON);
             })
             .setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED));
     }

+ 32 - 29
ruoyi-gateway-mvc/src/main/java/org/dromara/gateway/filter/AuthFilter.java

@@ -3,7 +3,6 @@ package org.dromara.gateway.filter;
 import cn.dev33.satoken.exception.NotLoginException;
 import cn.dev33.satoken.filter.SaServletFilter;
 import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil;
-import cn.dev33.satoken.interceptor.SaInterceptor;
 import cn.dev33.satoken.router.SaRouter;
 import cn.dev33.satoken.stp.StpUtil;
 import cn.dev33.satoken.util.SaResult;
@@ -14,23 +13,19 @@ import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.gateway.config.properties.IgnoreWhiteProperties;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.core.Ordered;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
 /**
- * [Sa-Token 权限认证] 拦截器配置
+ * [Sa-Token 权限认证] 过滤器配置
  *
  * @author Lion Li
  */
 @Configuration
-public class AuthFilter implements WebMvcConfigurer {
+public class AuthFilter {
 
     private final IgnoreWhiteProperties ignoreWhite;
 
@@ -38,31 +33,39 @@ public class AuthFilter implements WebMvcConfigurer {
         this.ignoreWhite = ignoreWhite;
     }
 
-    @Override
-    public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(new SaInterceptor(handler -> SaRouter.match("/**")
-            .notMatch(ignoreWhite.getWhites())
-            .check(() -> {
-                HttpServletRequest request = ServletUtils.getRequest();
-                HttpServletResponse response = ServletUtils.getResponse();
-                if (response != null) {
-                    response.setContentType(SaTokenConsts.CONTENT_TYPE_APPLICATION_JSON);
-                }
+    /**
+     * 注册 Sa-Token 全局过滤器
+     */
+    @Bean
+    public SaServletFilter authSaServletFilter() {
+        return new SaServletFilter()
+            .addInclude("/**")
+            .addExclude("/favicon.ico", "/actuator", "/actuator/**", "/resource/sse")
+            .setAuth(obj -> SaRouter.match("/**")
+                .notMatch(ignoreWhite.getWhites())
+                .check(() -> {
+                    HttpServletRequest request = ServletUtils.getRequest();
 
-                StpUtil.checkLogin();
+                    StpUtil.checkLogin();
 
-                String headerCid = request.getHeader(LoginHelper.CLIENT_KEY);
-                String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
-                Object extra = StpUtil.getExtra(LoginHelper.CLIENT_KEY);
-                String clientId = extra == null ? null : extra.toString();
-                if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
-                    throw NotLoginException.newInstance(StpUtil.getLoginType(),
-                        "-100", "客户端ID与Token不匹配",
-                        StpUtil.getTokenValue());
+                    String headerCid = request.getHeader(LoginHelper.CLIENT_KEY);
+                    String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
+                    Object extra = StpUtil.getExtra(LoginHelper.CLIENT_KEY);
+                    String clientId = extra == null ? null : extra.toString();
+                    if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
+                        throw NotLoginException.newInstance(StpUtil.getLoginType(),
+                            "-100", "客户端ID与Token不匹配",
+                            StpUtil.getTokenValue());
+                    }
+                }))
+            .setError(e -> {
+                HttpServletResponse response = ServletUtils.getResponse();
+                response.setContentType(SaTokenConsts.CONTENT_TYPE_APPLICATION_JSON);
+                if (e instanceof NotLoginException) {
+                    return SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED);
                 }
-            })))
-            .addPathPatterns("/**")
-            .excludePathPatterns("/favicon.ico", "/actuator", "/actuator/**", "/resource/sse");
+                return SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED);
+            });
     }
 
     /**

+ 0 - 2
ruoyi-gateway/src/main/java/org/dromara/gateway/filter/AuthFilter.java

@@ -63,8 +63,6 @@ public class AuthFilter {
                         // }
                     });
             }).setError(e -> {
-                ServerHttpResponse response = SaReactorSyncHolder.getExchange().getResponse();
-                response.getHeaders().set(SaTokenConsts.CONTENT_TYPE_KEY, SaTokenConsts.CONTENT_TYPE_APPLICATION_JSON);
                 if (e instanceof NotLoginException) {
                     return SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED);
                 }

+ 0 - 13
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java

@@ -157,19 +157,6 @@ public class GenController extends BaseController {
         genCode(response, data);
     }
 
-    /**
-     * 生成代码(自定义路径)
-     *
-     * @param tableId 表ID
-     */
-    @SaCheckPermission("tool:gen:code")
-    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
-    @GetMapping("/genCode/{tableId}")
-    public R<Void> genCode(@PathVariable("tableId") Long tableId) {
-        genTableService.generatorCode(tableId);
-        return R.ok();
-    }
-
     /**
      * 同步数据库
      *

+ 2 - 2
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTable.java

@@ -101,12 +101,12 @@ public class GenTable extends BaseEntity {
     private String functionAuthor;
 
     /**
-     * 生成代码方式(0zip压缩包 1自定义路径
+     * 生成代码方式(固定为0zip压缩包)
      */
     private String genType;
 
     /**
-     * 生成路径(不填默认项目路径
+     * 生成路径(兼容历史字段
      */
     @TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
     private String genPath;

+ 2 - 50
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java

@@ -23,7 +23,6 @@ import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.SpringUtils;
 import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.core.utils.file.FileUtils;
 import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -40,7 +39,6 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.ByteArrayOutputStream;
-import java.io.File;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.nio.charset.StandardCharsets;
@@ -222,6 +220,8 @@ public class GenTableServiceImpl implements IGenTableService {
     @Transactional(rollbackFor = Exception.class)
     @Override
     public void updateGenTable(GenTable genTable) {
+        genTable.setGenType("0");
+        genTable.setGenPath("/");
         String options = JsonUtils.toJsonString(genTable.getParams());
         genTable.setOptions(options);
         int row = baseMapper.updateById(genTable);
@@ -357,40 +357,6 @@ public class GenTableServiceImpl implements IGenTableService {
         return outputStream.toByteArray();
     }
 
-    /**
-     * 生成代码(自定义路径)
-     *
-     * @param tableId 表名称
-     */
-    @Override
-    public void generatorCode(Long tableId) {
-        // 查询表信息
-        GenTable table = baseMapper.selectGenTableById(tableId);
-        // 设置主键列信息
-        setPkColumn(table);
-
-        VelocityInitializer.initVelocity();
-
-        VelocityContext context = VelocityUtils.prepareContext(table);
-
-        // 获取模板列表
-        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getDataName());
-        for (String template : templates) {
-            if (!StringUtils.containsAny(template, "sql.vm", "api.ts.vm", "types.ts.vm", "index.vue.vm", "index-tree.vue.vm")) {
-                // 渲染模板
-                StringWriter sw = new StringWriter();
-                Template tpl = Velocity.getTemplate(template, Constants.UTF8);
-                tpl.merge(context, sw);
-                try {
-                    String path = getGenPath(table, template);
-                    FileUtils.writeUtf8String(sw.toString(), path);
-                } catch (Exception e) {
-                    throw new ServiceException("渲染模板失败,表名:" + table.getTableName());
-                }
-            }
-        }
-    }
-
     /**
      * 同步数据库
      *
@@ -560,19 +526,5 @@ public class GenTableServiceImpl implements IGenTableService {
         }
     }
 
-    /**
-     * 获取代码生成地址
-     *
-     * @param table    业务表信息
-     * @param template 模板文件路径
-     * @return 生成地址
-     */
-    public static String getGenPath(GenTable table, String template) {
-        String genPath = table.getGenPath();
-        if (StringUtils.equals(genPath, "/")) {
-            return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
-        }
-        return genPath + File.separator + VelocityUtils.getFileName(template, table);
-    }
 }
 

+ 0 - 7
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java

@@ -110,13 +110,6 @@ public interface IGenTableService {
      */
     byte[] downloadCode(Long tableId);
 
-    /**
-     * 生成代码(自定义路径)
-     *
-     * @param tableId 表名称
-     */
-    void generatorCode(Long tableId);
-
     /**
      * 同步数据库
      *

+ 5 - 3
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java

@@ -162,9 +162,11 @@ public class WorkflowGlobalListener implements GlobalListener {
         String[] userIdArray = userIds.split(StringUtils.SEPARATOR);
         if (userIdArray.length > 0) {
             flowTask.setPermissionList(List.of(userIdArray));
-            // 移除已处理的状态变量
-            variable.remove(nodeKey);
-            FlowEngine.insService().removeVariables(flowTask.getInstanceId(), nodeKey);
+            if (TaskStatusEnum.PASS.getStatus().equals(taskStatus)) {
+                // 办理指定人变量只消费一次;驳回指定人变量需要保留给后续重复驳回。
+                variable.remove(nodeKey);
+                FlowEngine.insService().removeVariables(flowTask.getInstanceId(), nodeKey);
+            }
         }
     }
 

+ 1 - 0
script/config/nacos/application-common.yml

@@ -230,6 +230,7 @@ xss:
   enabled: true
   excludeUrls:
     - /system/notice
+    - /warm-flow/save-json
 
 # 接口文档配置
 springdoc:

+ 11 - 11
script/docker/docker-compose.yml

@@ -27,7 +27,7 @@ services:
     network_mode: "host"
 
   nacos:
-    image: ruoyi/ruoyi-nacos:2.6.1
+    image: ruoyi/ruoyi-nacos:2.6.2
     container_name: nacos
     ports:
       - "8848:8848"
@@ -95,7 +95,7 @@ services:
     network_mode: "host"
 
   seata-server:
-    image: ruoyi/ruoyi-seata-server:2.6.1
+    image: ruoyi/ruoyi-seata-server:2.6.2
     container_name: seata-server
     ports:
       - "7091:7091"
@@ -134,7 +134,7 @@ services:
     network_mode: "host"
 
   ruoyi-monitor:
-    image: ruoyi/ruoyi-monitor:2.6.1
+    image: ruoyi/ruoyi-monitor:2.6.2
     container_name: ruoyi-monitor
     environment:
       # 时区上海
@@ -150,7 +150,7 @@ services:
     network_mode: "host"
 
   ruoyi-snailjob-server:
-    image: ruoyi/ruoyi-snailjob-server:2.6.1
+    image: ruoyi/ruoyi-snailjob-server:2.6.2
     container_name: ruoyi-snailjob-server
     environment:
       # 时区上海
@@ -164,7 +164,7 @@ services:
     network_mode: "host"
 
   ruoyi-gateway:
-    image: ruoyi/ruoyi-gateway:2.6.1
+    image: ruoyi/ruoyi-gateway:2.6.2
     container_name: ruoyi-gateway
     environment:
       # 时区上海
@@ -180,7 +180,7 @@ services:
     network_mode: "host"
 
   ruoyi-auth:
-    image: ruoyi/ruoyi-auth:2.6.1
+    image: ruoyi/ruoyi-auth:2.6.2
     container_name: ruoyi-auth
     environment:
       # 时区上海
@@ -196,7 +196,7 @@ services:
     network_mode: "host"
 
   ruoyi-system:
-    image: ruoyi/ruoyi-system:2.6.1
+    image: ruoyi/ruoyi-system:2.6.2
     container_name: ruoyi-system
     environment:
       # 时区上海
@@ -212,7 +212,7 @@ services:
     network_mode: "host"
 
   ruoyi-gen:
-    image: ruoyi/ruoyi-gen:2.6.1
+    image: ruoyi/ruoyi-gen:2.6.2
     container_name: ruoyi-gen
     environment:
       # 时区上海
@@ -228,7 +228,7 @@ services:
     network_mode: "host"
 
   ruoyi-job:
-    image: ruoyi/ruoyi-job:2.6.1
+    image: ruoyi/ruoyi-job:2.6.2
     container_name: ruoyi-job
     environment:
       # 时区上海
@@ -246,7 +246,7 @@ services:
     network_mode: "host"
 
   ruoyi-resource:
-    image: ruoyi/ruoyi-resource:2.6.1
+    image: ruoyi/ruoyi-resource:2.6.2
     container_name: ruoyi-resource
     environment:
       # 时区上海
@@ -262,7 +262,7 @@ services:
     network_mode: "host"
 
   ruoyi-workflow:
-    image: ruoyi/ruoyi-workflow:2.6.1
+    image: ruoyi/ruoyi-workflow:2.6.2
     container_name: ruoyi-workflow
     environment:
       # 时区上海