diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java index d685fd81a..b4faa4645 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java @@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; import com.baomidou.mybatisplus.extension.incrementer.*; +import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal; +import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.apache.ibatis.annotations.Mapper; @@ -16,16 +18,26 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.core.env.ConfigurableEnvironment; +import java.util.concurrent.TimeUnit; + /** * MyBaits 配置类 * * @author 芋道源码 */ -@AutoConfiguration(before = MybatisPlusAutoConfiguration.class) // 目的:先于 MyBatis Plus 自动配置,避免 @MapperScan 可能扫描不到 Mapper 打印 warn 日志 +@AutoConfiguration(before = MybatisPlusAutoConfiguration.class) +// 目的:先于 MyBatis Plus 自动配置,避免 @MapperScan 可能扫描不到 Mapper 打印 warn 日志 @MapperScan(value = "${yudao.info.base-package}", annotationClass = Mapper.class, lazyInitialization = "${mybatis.lazy-initialization:false}") // Mapper 懒加载,目前仅用于单元测试 public class YudaoMybatisAutoConfiguration { + static { + JsqlParserGlobal.setJsqlParseCache(new JdkSerialCaffeineJsqlParseCache( + (cache) -> cache.maximumSize(1024) + .expireAfterWrite(5, TimeUnit.SECONDS)) + ); + } + @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); @@ -34,7 +46,7 @@ public class YudaoMybatisAutoConfiguration { } @Bean - public MetaObjectHandler defaultMetaObjectHandler(){ + public MetaObjectHandler defaultMetaObjectHandler() { return new DefaultDBFieldHandler(); // 自动填充参数类 } @@ -61,4 +73,5 @@ public class YudaoMybatisAutoConfiguration { throw new IllegalArgumentException(StrUtil.format("DbType{} 找不到合适的 IKeyGenerator 实现类", dbType)); } + } diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java index 3259dac11..0af3adba2 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/aop/ApiSignatureAspect.java @@ -69,7 +69,7 @@ public class ApiSignatureAspect { // 3. 将 nonce 记入缓存,防止重复使用(重点二:此处需要将 ttl 设定为允许 timestamp 时间差的值 x 2 ) String nonce = request.getHeader(signature.nonce()); - signatureRedisDAO.setNonce(nonce, signature.timeout() * 2, signature.timeUnit()); + signatureRedisDAO.setNonce(appId, nonce, signature.timeout() * 2, signature.timeUnit()); return true; } @@ -113,7 +113,7 @@ public class ApiSignatureAspect { } // 3. 检查 nonce 是否存在,有且仅能使用一次 - return signatureRedisDAO.getNonce(nonce) == null; + return signatureRedisDAO.getNonce(appId, nonce) == null; } /** diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java index f4aa84910..11fe384da 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/signature/core/redis/ApiSignatureRedisDAO.java @@ -22,7 +22,7 @@ public class ApiSignatureRedisDAO { * VALUE 格式:String * 过期时间:不固定 */ - private static final String SIGNATURE_NONCE = "api_signature_nonce:%s"; + private static final String SIGNATURE_NONCE = "api_signature_nonce:%s:%s"; /** * 签名密钥 @@ -36,16 +36,16 @@ public class ApiSignatureRedisDAO { // ========== 验签随机数 ========== - public String getNonce(String nonce) { - return stringRedisTemplate.opsForValue().get(formatNonceKey(nonce)); + public String getNonce(String appId, String nonce) { + return stringRedisTemplate.opsForValue().get(formatNonceKey(appId, nonce)); } - public void setNonce(String nonce, int time, TimeUnit timeUnit) { - stringRedisTemplate.opsForValue().set(formatNonceKey(nonce), "", time, timeUnit); + public void setNonce(String appId, String nonce, int time, TimeUnit timeUnit) { + stringRedisTemplate.opsForValue().set(formatNonceKey(appId, nonce), "", time, timeUnit); } - private static String formatNonceKey(String key) { - return String.format(SIGNATURE_NONCE, key); + private static String formatNonceKey(String appId, String nonce) { + return String.format(SIGNATURE_NONCE, appId, nonce); } // ========== 签名密钥 ========== diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/test/java/cn/iocoder/yudao/framework/signature/core/ApiSignatureTest.java b/yudao-framework/yudao-spring-boot-starter-protection/src/test/java/cn/iocoder/yudao/framework/signature/core/ApiSignatureTest.java index c9a3dfff4..2b467c51d 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/test/java/cn/iocoder/yudao/framework/signature/core/ApiSignatureTest.java +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/test/java/cn/iocoder/yudao/framework/signature/core/ApiSignatureTest.java @@ -69,7 +69,7 @@ public class ApiSignatureTest { // 断言结果 assertTrue(result); // 断言调用 - verify(signatureRedisDAO).setNonce(eq(nonce), eq(120), eq(TimeUnit.SECONDS)); + verify(signatureRedisDAO).setNonce(eq(appId), eq(nonce), eq(120), eq(TimeUnit.SECONDS)); } } diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java index d6aeb3bf0..fea853e7c 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; import com.mzt.logapi.beans.LogRecord; import com.mzt.logapi.service.ILogRecordService; @@ -17,7 +16,7 @@ import java.util.List; /** * 操作日志 ILogRecordService 实现类 * - * 基于 {@link OperateLogApi} 实现,记录操作日志 + * 基于 {@link OperateLogFrameworkService}实现, 记录操作日志 * * @author HUIHUI */ @@ -25,7 +24,7 @@ import java.util.List; public class LogRecordServiceImpl implements ILogRecordService { @Resource - private OperateLogApi operateLogApi; + OperateLogFrameworkService operateLogFrameworkService; @Override public void record(LogRecord logRecord) { @@ -40,7 +39,7 @@ public class LogRecordServiceImpl implements ILogRecordService { fillRequestFields(reqDTO); // 2. 异步记录日志 - operateLogApi.createOperateLog(reqDTO); + operateLogFrameworkService.createOperateLog(reqDTO); } private static void fillUserFields(OperateLogCreateReqDTO reqDTO) { diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/OperateLogFrameworkService.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/OperateLogFrameworkService.java new file mode 100644 index 000000000..cf2cf5b00 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/OperateLogFrameworkService.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.framework.operatelog.core.service; + +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; + +/** + * API 操作日志 Framework Service 接口 + * + * @author 陈晨成 + */ +public interface OperateLogFrameworkService { + + /** + * 创建 操作日志 + * + * @param reqDTO API 操作日志 + */ + void createOperateLog(OperateLogCreateReqDTO reqDTO); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/OperateLogFrameworkServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/OperateLogFrameworkServiceImpl.java new file mode 100644 index 000000000..aa97689ac --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/OperateLogFrameworkServiceImpl.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.framework.operatelog.core.service; + +import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; + +/** + * API 操作日志 Framework Service 实现类 + * + * 基于 {@link OperateLogApi} 服务,记录操作日志 + * + * @author 陈晨成 + */ +@RequiredArgsConstructor +@Slf4j +public class OperateLogFrameworkServiceImpl implements OperateLogFrameworkService { + + private final OperateLogApi operateLogApi; + + @Override + @Async + public void createOperateLog(OperateLogCreateReqDTO reqDTO) { + try { + operateLogApi.createOperateLog(reqDTO); + } catch (Throwable ex) { + // 由于 @Async 异步调用,这里打印下日志,更容易跟进 + log.error("[createOperateLog][url({}) log({}) 发生异常]", reqDTO.getRequestUrl(), reqDTO, ex); + } + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java index a24999176..a94fb878e 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java @@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import jakarta.annotation.Resource; import org.springframework.beans.factory.config.MethodInvokingFactoryBean; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureOrder; @@ -21,11 +22,9 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.access.AccessDeniedHandler; -import jakarta.annotation.Resource; - /** * Spring Security 自动配置类,主要用于相关组件的配置 - * + *

* 注意,不能和 {@link YudaoWebSecurityConfigurerAdapter} 用一个,原因是会导致初始化报错。 * 参见 https://stackoverflow.com/questions/53847050/spring-boot-delegatebuilder-cannot-be-null-on-autowiring-authenticationmanager 文档。 *