diff --git a/README.md b/README.md index 72b693042..c881b5de9 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,7 @@ ps:核心功能已经实现,正在对接微信小程序中... | [Seata](https://github.com/seata/seata) | 分布式事务 | 1.6.1 | [文档](https://www.iocoder.cn/categories/Seata/?yudao) | | [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 / 8.0+ | | | [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.15 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | -| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.2 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) | +| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.5.3.1 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) | | [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) | | [Redis](https://redis.io/) | key-value 数据库 | 5.0 / 6.0 | | | [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.18.0 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) | @@ -221,9 +221,9 @@ ps:核心功能已经实现,正在对接微信小程序中... | [Spring Security](https://github.com/spring-projects/spring-security) | Spring 安全框架 | 5.7.5 | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) | | [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.2.5 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) | | [Flowable](https://github.com/flowable/flowable-engine) | 工作流引擎 | 6.7.2 | [文档](https://doc.iocoder.cn/bpm/) | -| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.3 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) | +| [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 4.0.0 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) | | [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.12.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) | -| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.9 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) | +| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 2.7.10 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) | | [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.13.3 | | | [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.5.3.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) | | [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.18.24 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) | @@ -242,12 +242,12 @@ ps:核心功能已经实现,正在对接微信小程序中... | 框架 | 说明 | 版本 | |----------------------------------------------------------------------|:------------:|:------:| | [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.2.45 | -| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.0.3 | -| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.27 | +| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.0.4 | +| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.2.28 | | [TypeScript](https://www.typescriptlang.org/docs/) | TypeScript | 4.9.4 | -| [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.28 | +| [pinia](https://pinia.vuejs.org/) | vuex5 | 2.0.29 | | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2 | -| [vxe-table](https://vxetable.cn/) | vue最强表单 | 4.3.7 | +| [vxe-table](https://vxetable.cn/) | vue最强表单 | 4.3.9 | ### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp) diff --git a/pom.xml b/pom.xml index e2149ae58..7b47417c0 100644 --- a/pom.xml +++ b/pom.xml @@ -24,15 +24,16 @@ https://github.com/YunaiV/ruoyi-vue-pro - 1.6.5-snapshot + 1.6.6-snapshot 1.8 ${java.version} ${java.version} 3.0.0-M5 - 3.8.0 + 3.8.1 1.18.24 + 2.7.7 1.5.3.Final UTF-8 @@ -60,12 +61,18 @@ ${maven-surefire-plugin.version} + org.apache.maven.plugins maven-compiler-plugin ${maven-compiler-plugin.version} + + org.springframework.boot + spring-boot-configuration-processor + ${spring.boot.version} + org.projectlombok lombok diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 0158649db..9411b4c74 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -14,23 +14,23 @@ https://github.com/YunaiV/ruoyi-vue-pro - 1.6.5-snapshot + 1.6.6-snapshot 2.7.7 2021.0.5 2021.0.4.0 - 3.0.3 + 4.0.0 1.6.8 2.5 1.2.15 - 3.5.3 - 3.5.2 + 3.5.3.1 + 3.5.3.1 3.6.1 3.18.0 - 2.7.15 + 2.7.18 1.9.2 @@ -40,19 +40,21 @@ 1.7.1 8.12.0 - 2.7.9 + 2.7.10 0.33.0 7.2.11.RELEASE 1.0.5 - 4.8.0 + 4.11.0 6.8.0 + 1.0.1 + 1.15.3 1.18.24 1.5.3.Final 5.8.11 - 3.1.3 + 3.1.5 2.3 1.0.5 1.2.83 @@ -61,17 +63,16 @@ 2.14.2 3.8.0 0.1.55 - 2.5.0 - 1.3.0 + 2.6.0 4.1.86.Final 2.6.6 3.0.0 4.10.0 - 8.4.6 + 8.5.1 4.6.3 2.2.1 - 3.1.660 + 3.1.676 1.4.0 @@ -191,7 +192,7 @@ com.github.xiaoymin - knife4j-spring-boot-starter + knife4j-openapi2-spring-boot-starter ${knife4j.version} @@ -501,12 +502,6 @@ ${tika-core.version} - - com.anji-plus - spring-boot-starter-captcha - ${aj-captcha.version} - - org.apache.velocity velocity-engine-core @@ -570,12 +565,24 @@ ${netty-all.version} + + com.xingyuv + spring-boot-starter-captcha-plus + ${captcha-plus.version} + + org.lionsoul ip2region ${ip2region.version} + + org.jsoup + jsoup + ${jsoup.version} + + com.squareup.okio diff --git a/yudao-framework/yudao-common/pom.xml b/yudao-framework/yudao-common/pom.xml index 23ce31370..45a0331dc 100644 --- a/yudao-framework/yudao-common/pom.xml +++ b/yudao-framework/yudao-common/pom.xml @@ -133,6 +133,11 @@ transmittable-thread-local + + org.jsoup + jsoup + + diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml b/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml index a355306df..4fd943b61 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml @@ -52,7 +52,7 @@ com.alipay.sdk alipay-sdk-java - 4.31.72.ALL + 4.35.32.ALL org.bouncycastle diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/pom.xml b/yudao-framework/yudao-spring-boot-starter-captcha/pom.xml index 4bc948fe1..b77ef8886 100644 --- a/yudao-framework/yudao-spring-boot-starter-captcha/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-captcha/pom.xml @@ -17,6 +17,11 @@ + + + com.xingyuv + spring-boot-starter-captcha-plus + org.springframework.boot @@ -29,11 +34,6 @@ yudao-spring-boot-starter-redis - - - com.anji-plus - spring-boot-starter-captcha - diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/config/YudaoCaptchaConfiguration.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/config/YudaoCaptchaConfiguration.java index f446819e7..2a690d800 100644 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/config/YudaoCaptchaConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/config/YudaoCaptchaConfiguration.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.captcha.config; import cn.hutool.core.util.ClassUtil; import cn.iocoder.yudao.framework.captcha.core.enums.CaptchaRedisKeyConstants; import cn.iocoder.yudao.framework.captcha.core.service.RedisCaptchaServiceImpl; -import com.anji.captcha.service.CaptchaCacheService; +import com.xingyuv.captcha.service.CaptchaCacheService; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.core.StringRedisTemplate; diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/enums/CaptchaRedisKeyConstants.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/enums/CaptchaRedisKeyConstants.java index db051ca69..3e1147c37 100644 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/enums/CaptchaRedisKeyConstants.java +++ b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/enums/CaptchaRedisKeyConstants.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.framework.captcha.core.enums; import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine; -import com.anji.captcha.model.vo.PointVO; +import com.xingyuv.captcha.model.vo.PointVO; import java.time.Duration; diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/service/RedisCaptchaServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/service/RedisCaptchaServiceImpl.java index c14901efb..1429c47c2 100644 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/service/RedisCaptchaServiceImpl.java +++ b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/service/RedisCaptchaServiceImpl.java @@ -1,9 +1,8 @@ package cn.iocoder.yudao.framework.captcha.core.service; -import com.anji.captcha.service.CaptchaCacheService; +import com.xingyuv.captcha.service.CaptchaCacheService; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.StringRedisTemplate; import javax.annotation.Resource; diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/services/com.xingyuv.captcha.service.CaptchaCacheService similarity index 100% rename from yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService rename to yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/services/com.xingyuv.captcha.service.CaptchaCacheService diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/spring.factories deleted file mode 100644 index ed8b528ff..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - cn.iocoder.yudao.framework.captcha.config.YudaoCaptchaConfiguration diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..8411d2cc3 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +cn.iocoder.yudao.framework.captcha.config.YudaoCaptchaConfiguration \ No newline at end of file diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java index fb4af6d69..4e945b0d2 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java @@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.baomidou.mybatisplus.extension.toolkit.Db; import org.apache.ibatis.annotations.Param; import java.util.Collection; @@ -87,8 +88,21 @@ public interface BaseMapperX extends BaseMapper { entities.forEach(this::insert); } + /** + * 批量插入,适合大量数据插入 + * + * @param entities 实体们 + * @param size 插入数量 Db.saveBatch 默认为1000 + */ + default void insertBatch(Collection entities, int size) { + Db.saveBatch(entities, size); + } + default void updateBatch(T update) { update(update, new QueryWrapper<>()); } + default void updateBatch(Collection entities, int size) { + Db.updateBatchById(entities, size); + } } diff --git a/yudao-framework/yudao-spring-boot-starter-web/pom.xml b/yudao-framework/yudao-spring-boot-starter-web/pom.xml index a04a2f1b0..790dc5ebd 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-web/pom.xml @@ -35,7 +35,7 @@ com.github.xiaoymin - knife4j-spring-boot-starter + knife4j-openapi2-spring-boot-starter io.swagger diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java index 4c114b519..5ccbc06c4 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/swagger/config/YudaoSwaggerAutoConfiguration.java @@ -7,18 +7,18 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.ExampleBuilder; +import springfox.documentation.builders.ParameterBuilder; import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestParameterBuilder; +import springfox.documentation.schema.ModelRef; import springfox.documentation.service.*; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; +import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -31,7 +31,7 @@ import static springfox.documentation.builders.RequestHandlerSelectors.basePacka * @author 芋道源码 */ @AutoConfiguration -@EnableSwagger2 +@EnableSwagger2WebMvc @EnableKnife4j @ConditionalOnClass({Docket.class, ApiInfoBuilder.class}) // 允许使用 swagger.enable=false 禁用 Swagger @@ -60,7 +60,7 @@ public class YudaoSwaggerAutoConfiguration { .securitySchemes(securitySchemes()) .securityContexts(securityContexts()) // ④ 全局参数(多租户 header) - .globalRequestParameters(globalRequestParameters()); + .globalOperationParameters(globalRequestParameters()); } // ========== apiInfo ========== @@ -96,7 +96,7 @@ public class YudaoSwaggerAutoConfiguration { return Collections.singletonList(SecurityContext.builder() .securityReferences(securityReferences()) // 通过 PathSelectors.regex("^(?!auth).*$"),排除包含 "auth" 的接口不需要使用securitySchemes - .operationSelector(o -> o.requestMappingPattern().matches("^(?!auth).*$")) + .forPaths(PathSelectors.regex("^(?!auth).*$")) .build()); } @@ -110,11 +110,17 @@ public class YudaoSwaggerAutoConfiguration { // ========== globalRequestParameters ========== - private static List globalRequestParameters() { - RequestParameterBuilder tenantParameter = new RequestParameterBuilder() - .name(HEADER_TENANT_ID).description("租户编号") - .in(ParameterType.HEADER).example(new ExampleBuilder().value(1L).build()); - return Collections.singletonList(tenantParameter.build()); + private static List globalRequestParameters() { + List tenantParameter = new ArrayList<>(); + tenantParameter.add(new ParameterBuilder() + .name(HEADER_TENANT_ID) + .description("租户编号") + .modelRef(new ModelRef("long")) + .defaultValue("1") + .parameterType("header") + .required(true) + .build()); + return tenantParameter; } } diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java index 5ab89bf1d..50586d4a6 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java @@ -2,15 +2,22 @@ package cn.iocoder.yudao.framework.web.config; import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService; import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; +import cn.iocoder.yudao.framework.web.core.clean.JsoupXssCleaner; +import cn.iocoder.yudao.framework.web.core.clean.XssCleaner; import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyFilter; import cn.iocoder.yudao.framework.web.core.filter.DemoFilter; import cn.iocoder.yudao.framework.web.core.filter.XssFilter; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler; +import cn.iocoder.yudao.framework.web.core.json.XssStringJsonDeserializer; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; +import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; @@ -48,7 +55,7 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { * 设置 API 前缀,仅仅匹配 controller 包下的 * * @param configurer 配置 - * @param api API 配置 + * @param api API 配置 */ private void configurePathMatch(PathMatchConfigurer configurer, WebProperties.Api api) { AntPathMatcher antPathMatcher = new AntPathMatcher("."); @@ -104,8 +111,9 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { * 创建 XssFilter Bean,解决 Xss 安全问题 */ @Bean - public FilterRegistrationBean xssFilter(XssProperties properties, PathMatcher mvcPathMatcher) { - return createFilterBean(new XssFilter(properties, mvcPathMatcher), WebFilterOrderEnum.XSS_FILTER); + @ConditionalOnBean(XssCleaner.class) + public FilterRegistrationBean xssFilter(XssProperties properties, PathMatcher pathMatcher, XssCleaner xssCleaner) { + return createFilterBean(new XssFilter(properties, pathMatcher, xssCleaner), WebFilterOrderEnum.XSS_FILTER); } /** @@ -117,6 +125,32 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { return createFilterBean(new DemoFilter(), WebFilterOrderEnum.DEMO_FILTER); } + + /** + * Xss 清理者 + * + * @return XssCleaner + */ + @ConditionalOnMissingBean(XssCleaner.class) + @Bean + public XssCleaner xssCleaner() { + return new JsoupXssCleaner(); + } + + /** + * 注册 Jackson 的序列化器,用于处理 json 类型参数的 xss 过滤 + * + * @return Jackson2ObjectMapperBuilderCustomizer + */ + @Bean + @ConditionalOnMissingBean(name = "xssJacksonCustomizer") + @ConditionalOnBean(ObjectMapper.class) + public Jackson2ObjectMapperBuilderCustomizer xssJacksonCustomizer(XssCleaner xssCleaner, XssProperties xssProperties) { + // 在反序列化时进行 xss 过滤,可以替换使用 XssStringJsonSerializer,在序列化时进行处理 + return builder -> builder.deserializerByType(String.class, new XssStringJsonDeserializer(xssCleaner, xssProperties)); + } + + private static FilterRegistrationBean createFilterBean(T filter, Integer order) { FilterRegistrationBean bean = new FilterRegistrationBean<>(filter); bean.setOrder(order); diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java new file mode 100644 index 000000000..559267c3f --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.framework.web.core.clean; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.safety.Safelist; + +/** + * jsonp 过滤字符串 + */ +public class JsoupXssCleaner implements XssCleaner { + + private final Safelist safelist; + + /** + * 用于在 src 属性使用相对路径时,强制转换为绝对路径。 为空时不处理,值应为绝对路径的前缀(包含协议部分) + */ + private final String baseUri; + + /** + * 无参构造,默认使用 {@link JsoupXssCleaner#buildSafelist} 方法构建一个安全列表 + */ + public JsoupXssCleaner() { + this.safelist = buildSafelist(); + this.baseUri = ""; + } + + public JsoupXssCleaner(Safelist safelist) { + this.safelist = safelist; + this.baseUri = ""; + } + + public JsoupXssCleaner(String baseUri) { + this.safelist = buildSafelist(); + this.baseUri = baseUri; + } + + public JsoupXssCleaner(Safelist safelist, String baseUri) { + this.safelist = safelist; + this.baseUri = baseUri; + } + + /** + * 构建一个 Xss 清理的 Safelist 规则。 + * 基于 Safelist#relaxed() 的基础上: + * 1. 扩展支持了 style 和 class 属性 + * 2. a 标签额外支持了 target 属性 + * 3. img 标签额外支持了 data 协议,便于支持 base64 + * + * @return Safelist + */ + private Safelist buildSafelist() { + // 使用 jsoup 提供的默认的 + Safelist relaxedSafelist = Safelist.relaxed(); + // 富文本编辑时一些样式是使用 style 来进行实现的 + // 比如红色字体 style="color:red;", 所以需要给所有标签添加 style 属性 + // 注意:style 属性会有注入风险 + relaxedSafelist.addAttributes(":all", "style", "class"); + // 保留 a 标签的 target 属性 + relaxedSafelist.addAttributes("a", "target"); + // 支持img 为base64 + relaxedSafelist.addProtocols("img", "src", "data"); + + // 保留相对路径, 保留相对路径时,必须提供对应的 baseUri 属性,否则依然会被删除 + // WHITELIST.preserveRelativeLinks(false); + + // 移除 a 标签和 img 标签的一些协议限制,这会导致 xss 防注入失效,如 + // 虽然可以重写 WhiteList#isSafeAttribute 来处理,但是有隐患,所以暂时不支持相对路径 + // WHITELIST.removeProtocols("a", "href", "ftp", "http", "https", "mailto"); + // WHITELIST.removeProtocols("img", "src", "http", "https"); + + return relaxedSafelist; + } + + @Override + public String clean(String html) { + return Jsoup.clean(html, baseUri, safelist, new Document.OutputSettings().prettyPrint(false)); + } + +} + diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java new file mode 100644 index 000000000..433f7e775 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.framework.web.core.clean; + +/** + * 对 html 文本中的有 Xss 风险的数据进行清理 + */ +public interface XssCleaner { + + /** + * 清理有 Xss 风险的文本 + * + * @param html 原 html + * @return 清理后的 html + */ + String clean(String html); +} diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java index 050a86cc1..2da18768d 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.framework.web.core.filter; import cn.iocoder.yudao.framework.web.config.XssProperties; +import cn.iocoder.yudao.framework.web.core.clean.XssCleaner; import lombok.AllArgsConstructor; import org.springframework.util.PathMatcher; import org.springframework.web.filter.OncePerRequestFilter; @@ -13,7 +14,7 @@ import java.io.IOException; /** * Xss 过滤器 - * + *

* 对 Xss 不了解的胖友,可以看看 http://www.iocoder.cn/Fight/The-new-girl-asked-me-why-AJAX-requests-are-not-secure-I-did-not-answer/ * * @author 芋道源码 @@ -30,10 +31,12 @@ public class XssFilter extends OncePerRequestFilter { */ private final PathMatcher pathMatcher; + private final XssCleaner xssCleaner; + @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { - filterChain.doFilter(new XssRequestWrapper(request), response); + filterChain.doFilter(new XssRequestWrapper(request, xssCleaner), response); } @Override diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java index 25bd20978..7beed46cc 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java @@ -1,21 +1,10 @@ package cn.iocoder.yudao.framework.web.core.filter; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.ReflectUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.http.HTMLFilter; -import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.web.core.clean.XssCleaner; -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStreamReader; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -24,113 +13,79 @@ import java.util.Map; * @author 芋道源码 */ public class XssRequestWrapper extends HttpServletRequestWrapper { + private final XssCleaner xssCleaner; - /** - * 基于线程级别的 HTMLFilter 对象,因为它线程非安全 - */ - private static final ThreadLocal HTML_FILTER = ThreadLocal.withInitial(() -> { - HTMLFilter htmlFilter = new HTMLFilter(); - // 反射修改 encodeQuotes 属性为 false,避免 " 被转移成 " 字符 - ReflectUtil.setFieldValue(htmlFilter, "encodeQuotes", false); - return htmlFilter; - }); - - public XssRequestWrapper(HttpServletRequest request) { + public XssRequestWrapper(HttpServletRequest request, XssCleaner xssCleaner) { super(request); + this.xssCleaner = xssCleaner; } - private static String filterXss(String content) { - if (StrUtil.isEmpty(content)) { - return content; + // ============================ parameter ============================ + @Override + public Map getParameterMap() { + Map map = new LinkedHashMap<>(); + Map parameters = super.getParameterMap(); + for (Map.Entry entry : parameters.entrySet()) { + String[] values = entry.getValue(); + for (int i = 0; i < values.length; i++) { + values[i] = xssCleaner.clean(values[i]); + } + map.put(entry.getKey(), values); } - return HTML_FILTER.get().filter(content); - } - - // ========== IO 流相关 ========== - - @Override - public BufferedReader getReader() throws IOException { - return new BufferedReader(new InputStreamReader(this.getInputStream())); - } - - @Override - public ServletInputStream getInputStream() throws IOException { - // 如果非 json 请求,不进行 Xss 处理 - if (!ServletUtils.isJsonRequest(this)) { - return super.getInputStream(); - } - - // 读取内容,并过滤 - String content = IoUtil.readUtf8(super.getInputStream()); - content = filterXss(content); - final ByteArrayInputStream newInputStream = new ByteArrayInputStream(content.getBytes()); - // 返回 ServletInputStream - return new ServletInputStream() { - - @Override - public int read() { - return newInputStream.read(); - } - - @Override - public boolean isFinished() { - return true; - } - - @Override - public boolean isReady() { - return true; - } - - @Override - public void setReadListener(ReadListener readListener) {} - - }; - } - - // ========== Param 相关 ========== - - @Override - public String getParameter(String name) { - String value = super.getParameter(name); - return filterXss(value); + return map; } @Override public String[] getParameterValues(String name) { String[] values = super.getParameterValues(name); - if (ArrayUtil.isEmpty(values)) { - return values; + if (values == null) { + return null; } - // 过滤处理 - for (int i = 0; i < values.length; i++) { - values[i] = filterXss(values[i]); + int count = values.length; + String[] encodedValues = new String[count]; + for (int i = 0; i < count; i++) { + encodedValues[i] = xssCleaner.clean(values[i]); } - return values; + return encodedValues; } @Override - public Map getParameterMap() { - Map valueMap = super.getParameterMap(); - if (CollUtil.isEmpty(valueMap)) { - return valueMap; + public String getParameter(String name) { + String value = super.getParameter(name); + if (value == null) { + return null; } - // 过滤处理 - for (Map.Entry entry : valueMap.entrySet()) { - String[] values = entry.getValue(); - for (int i = 0; i < values.length; i++) { - values[i] = filterXss(values[i]); - } - } - return valueMap; + return xssCleaner.clean(value); } - // ========== Header 相关 ========== + // ============================ attribute ============================ + @Override + public Object getAttribute(String name) { + Object value = super.getAttribute(name); + if (value instanceof String) { + xssCleaner.clean((String) value); + } + return value; + } + // ============================ header ============================ @Override public String getHeader(String name) { String value = super.getHeader(name); - return filterXss(value); + if (value == null) { + return null; + } + return xssCleaner.clean(value); + } + + // ============================ queryString ============================ + @Override + public String getQueryString() { + String value = super.getQueryString(); + if (value == null) { + return null; + } + return xssCleaner.clean(value); } } diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java new file mode 100644 index 000000000..7e1f631c7 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.framework.web.core.json; + +import cn.iocoder.yudao.framework.web.core.clean.XssCleaner; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StringDeserializer; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; + +/** + * XSS 过滤 jackson 反序列化器。 + * 在反序列化的过程中,会对字符串进行 XSS 过滤。 + * + * @author Hccake + */ +@Slf4j +@AllArgsConstructor +public class XssStringJsonDeserializer extends StringDeserializer { + + private final XssCleaner xssCleaner; + + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + if (p.hasToken(JsonToken.VALUE_STRING)) { + return xssCleaner.clean(p.getText()); + } + JsonToken t = p.currentToken(); + // [databind#381] + if (t == JsonToken.START_ARRAY) { + return _deserializeFromArray(p, ctxt); + } + // need to gracefully handle byte[] data, as base64 + if (t == JsonToken.VALUE_EMBEDDED_OBJECT) { + Object ob = p.getEmbeddedObject(); + if (ob == null) { + return null; + } + if (ob instanceof byte[]) { + return ctxt.getBase64Variant().encode((byte[]) ob, false); + } + // otherwise, try conversion using toString()... + return ob.toString(); + } + // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML) + if (t == JsonToken.START_OBJECT) { + return ctxt.extractScalarFromObject(p, this, _valueClass); + } + + if (t.isScalarValue()) { + String text = p.getValueAsString(); + return xssCleaner.clean(text); + } + return (String) ctxt.handleUnexpectedToken(_valueClass, p); + } +} + diff --git a/yudao-gateway/pom.xml b/yudao-gateway/pom.xml index 45ebc2ece..a0a03fd6d 100644 --- a/yudao-gateway/pom.xml +++ b/yudao-gateway/pom.xml @@ -46,7 +46,7 @@ com.github.xiaoymin - knife4j-spring-boot-starter + knife4j-openapi2-spring-boot-starter io.swagger diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java index b0df3e34f..1d286c52f 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java @@ -11,9 +11,11 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; import com.baomidou.mybatisplus.generator.config.po.TableField; import com.baomidou.mybatisplus.generator.config.po.TableInfo; +import org.apache.ibatis.type.JdbcType; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; +import org.mapstruct.Named; import org.mapstruct.factory.Mappers; import java.util.List; @@ -37,7 +39,7 @@ public interface CodegenConvert { @Mappings({ @Mapping(source = "name", target = "columnName"), - @Mapping(source = "type", target = "dataType"), + @Mapping(source = "metaInfo.jdbcType", target = "dataType", qualifiedByName = "getDataType"), @Mapping(source = "comment", target = "columnComment"), @Mapping(source = "metaInfo.nullable", target = "nullable"), @Mapping(source = "keyFlag", target = "primaryKey"), @@ -47,6 +49,11 @@ public interface CodegenConvert { }) CodegenColumnDO convert(TableField bean); + @Named("getDataType") + default String getDataType(JdbcType jdbcType) { + return jdbcType.name(); + } + // ========== CodegenTableDO 相关 ========== // List convertList02(List list); diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java index 4e7f330e5..f1990f3fc 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnListConditionEnu import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.generator.config.po.TableField; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; @@ -29,7 +30,7 @@ public class CodegenColumnDO extends BaseDO { private Long id; /** * 表编号 - * + *

* 关联 {@link CodegenTableDO#getId()} */ private Long tableId; @@ -41,7 +42,8 @@ public class CodegenColumnDO extends BaseDO { */ private String columnName; /** - * 字段类型 + * 数据库字段类型 + * 关联 {@link TableField.MetaInfo#getJdbcType()} */ private String dataType; /** @@ -69,7 +71,7 @@ public class CodegenColumnDO extends BaseDO { /** * Java 属性类型 - * + *

* 例如说 String、Boolean 等等 */ private String javaType; @@ -79,7 +81,7 @@ public class CodegenColumnDO extends BaseDO { private String javaField; /** * 字典类型 - * + *

* 关联 DictTypeDO 的 type 属性 */ private String dictType; @@ -104,7 +106,7 @@ public class CodegenColumnDO extends BaseDO { private Boolean listOperation; /** * List 查询操作的条件类型 - * + *

* 枚举 {@link CodegenColumnListConditionEnum} */ private String listOperationCondition; @@ -117,7 +119,7 @@ public class CodegenColumnDO extends BaseDO { /** * 显示类型 - * + *

* 枚举 {@link CodegenColumnHtmlTypeEnum} */ private String htmlType; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java index 41b1dae33..a6de8d9ee 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.infra.service; import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.generator.IDatabaseQuery.DefaultDatabaseQuery; +import com.baomidou.mybatisplus.generator.query.DefaultQuery; import com.baomidou.mybatisplus.generator.config.DataSourceConfig; import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder; import com.baomidou.mybatisplus.generator.config.po.TableInfo; @@ -19,7 +19,7 @@ public class DefaultDatabaseQueryTest { ConfigBuilder builder = new ConfigBuilder(null, dataSourceConfig, null, null, null, null); - DefaultDatabaseQuery query = new DefaultDatabaseQuery(builder); + DefaultQuery query = new DefaultQuery(builder); long time = System.currentTimeMillis(); List tableInfos = query.queryTables(); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java index 79046e984..9921c8ea8 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java @@ -1,8 +1,11 @@ package cn.iocoder.yudao.module.system.controller.admin.captcha; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.ServletUtil; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import com.anji.captcha.model.common.ResponseModel; -import com.anji.captcha.model.vo.CaptchaVO; +import com.xingyuv.captcha.model.common.ResponseModel; +import com.xingyuv.captcha.model.vo.CaptchaVO; +import com.xingyuv.captcha.service.CaptchaService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.PostMapping; @@ -10,38 +13,49 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Resource; import javax.annotation.security.PermitAll; import javax.servlet.http.HttpServletRequest; /** * 验证码 * - * 问题:为什么不直接使用 anji 提供的 CaptchaController,而要另外继承? - * 回答:管理使用 /admin-api/* 作为前缀,所以需要继承! - * * @author 芋道源码 */ @Api(tags = "管理后台 - 验证码") @RestController("adminCaptchaController") @RequestMapping("/system/captcha") -public class CaptchaController extends com.anji.captcha.controller.CaptchaController { +public class CaptchaController { - @PostMapping("/get") + @Resource + private CaptchaService captchaService; + + @PostMapping({"/get"}) @ApiOperation("获得验证码") @PermitAll @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 - @Override public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) { - return super.get(data, request); + assert request.getRemoteHost() != null; + data.setBrowserInfo(getRemoteId(request)); + return captchaService.get(data); } @PostMapping("/check") @ApiOperation("校验验证码") @PermitAll @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 - @Override public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) { - return super.check(data, request); + data.setBrowserInfo(getRemoteId(request)); + return captchaService.check(data); + } + + public static String getRemoteId(HttpServletRequest request) { + String ip = ServletUtil.getClientIP(request); + String ua = request.getHeader("user-agent"); + if (StrUtil.isNotBlank(ip)) { + return ip + ua; + } + return request.getRemoteAddr() + ua; } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java index ad1260500..045e3bf4b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java @@ -22,9 +22,9 @@ import cn.iocoder.yudao.module.system.service.member.MemberService; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; import cn.iocoder.yudao.module.system.service.social.SocialUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; -import com.anji.captcha.model.common.ResponseModel; -import com.anji.captcha.model.vo.CaptchaVO; -import com.anji.captcha.service.CaptchaService; +import com.xingyuv.captcha.model.common.ResponseModel; +import com.xingyuv.captcha.model.vo.CaptchaVO; +import com.xingyuv.captcha.service.CaptchaService; import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java index 902c4c887..b52ff9a8f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java @@ -14,7 +14,7 @@ import cn.iocoder.yudao.module.system.service.member.MemberService; import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; import cn.iocoder.yudao.module.system.service.social.SocialUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; -import com.anji.captcha.service.CaptchaService; +import com.xingyuv.captcha.service.CaptchaService; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import;