From 0ae9af04927fa3a161789e58037915537f8d2f5e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 19 May 2022 02:17:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20MyBatis=20Plus=20=E7=9A=84?= =?UTF-8?q?=20EncryptTypeHandler=20=E7=B1=BB=E5=9E=8B=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=99=A8=EF=BC=8C=E5=AE=9E=E7=8E=B0=E5=AD=97=E6=AE=B5=E7=9A=84?= =?UTF-8?q?=E5=8A=A0=E5=AF=86=E8=A7=A3=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao-spring-boot-starter-mybatis/pom.xml | 8 +++ .../mybatis/core/type/EncryptTypeHandler.java | 63 +++++++++++++++++++ ...andler.java => StringListTypeHandler.java} | 2 +- .../dal/dataobject/db/DataSourceConfigDO.java | 5 +- .../db/DataSourceConfigServiceImpl.java | 13 +--- .../db/DataSourceConfigServiceImplTest.java | 26 +++++--- .../sensitiveword/SensitiveWordDO.java | 4 +- .../tip/core/TipApplicationRunner.java | 2 +- 8 files changed, 99 insertions(+), 24 deletions(-) create mode 100644 yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java rename yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/{StringLiSTTypeHandler.java => StringListTypeHandler.java} (96%) diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml index 2d48df367..5567cedc7 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml @@ -58,6 +58,14 @@ com.baomidou dynamic-datasource-spring-boot-starter + + + + com.github.ulisesbocchio + jasypt-spring-boot-starter + true + + diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java new file mode 100644 index 000000000..da55e057c --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.framework.mybatis.core.type; + +import cn.hutool.core.lang.Assert; +import cn.hutool.extra.spring.SpringUtil; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; +import org.jasypt.encryption.StringEncryptor; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * 字段字段的 TypeHandler 实现类,基于 {@link StringEncryptor} 实现 + * 可通过 jasypt.encryptor.password 配置项,设置密钥 + * + * @author 芋道源码 + */ +public class EncryptTypeHandler extends BaseTypeHandler { + + private static StringEncryptor encryptor; + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { + ps.setString(i, getEncryptor().encrypt(parameter)); + } + + @Override + public String getNullableResult(ResultSet rs, String columnName) throws SQLException { + String value = rs.getString(columnName); + return getResult(value); + } + + @Override + public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + String value = rs.getString(columnIndex); + return getResult(value); + } + + @Override + public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + String value = cs.getString(columnIndex); + return getResult(value); + } + + private String getResult(String value) { + if (value == null) { + return null; + } + return getEncryptor().decrypt(value); + } + + private StringEncryptor getEncryptor() { + if (encryptor != null) { + return encryptor; + } + encryptor = SpringUtil.getBean(StringEncryptor.class); + Assert.notNull(encryptor, "StringEncryptor 不能为空"); + return encryptor; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringLiSTTypeHandler.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java similarity index 96% rename from yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringLiSTTypeHandler.java rename to yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java index f9811c418..598a15ef7 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringLiSTTypeHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java @@ -21,7 +21,7 @@ import java.util.List; */ @MappedJdbcTypes(JdbcType.VARCHAR) @MappedTypes(List.class) -public class StringLiSTTypeHandler implements TypeHandler> { +public class StringListTypeHandler implements TypeHandler> { private static final String COMMA = ","; diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java index 9b4c36084..138babe52 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.infra.dal.dataobject.db; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.EncryptTypeHandler; import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -10,7 +12,7 @@ import lombok.Data; * * @author 芋道源码 */ -@TableName("infra_data_source_config") +@TableName(value = "infra_data_source_config", autoResultMap = true) @KeySequence("infra_data_source_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data public class DataSourceConfigDO extends BaseDO { @@ -40,6 +42,7 @@ public class DataSourceConfigDO extends BaseDO { /** * 密码 */ + @TableField(typeHandler = EncryptTypeHandler.class) private String password; } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java index acc8faa1c..f2fd0a408 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java @@ -8,7 +8,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; import cn.iocoder.yudao.module.infra.dal.mysql.db.DataSourceConfigMapper; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; -import org.jasypt.encryption.StringEncryptor; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -32,9 +31,6 @@ public class DataSourceConfigServiceImpl implements DataSourceConfigService { @Resource private DataSourceConfigMapper dataSourceConfigMapper; - @Resource - private StringEncryptor stringEncryptor; - @Resource private DynamicDataSourceProperties dynamicDataSourceProperties; @@ -44,7 +40,6 @@ public class DataSourceConfigServiceImpl implements DataSourceConfigService { checkConnectionOK(dataSourceConfig); // 插入 - dataSourceConfig.setPassword(stringEncryptor.encrypt(createReqVO.getPassword())); dataSourceConfigMapper.insert(dataSourceConfig); // 返回 return dataSourceConfig.getId(); @@ -58,7 +53,6 @@ public class DataSourceConfigServiceImpl implements DataSourceConfigService { checkConnectionOK(updateObj); // 更新 - updateObj.setPassword(stringEncryptor.encrypt(updateObj.getPassword())); dataSourceConfigMapper.updateById(updateObj); } @@ -83,12 +77,7 @@ public class DataSourceConfigServiceImpl implements DataSourceConfigService { return buildMasterDataSourceConfig(); } // 从 DB 中读取 - DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(id); - try { - dataSourceConfig.setPassword(stringEncryptor.decrypt(dataSourceConfig.getPassword())); - } catch (Exception ignore) { // 解码失败,则不解码 - } - return dataSourceConfig; + return dataSourceConfigMapper.selectById(id); } @Override diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java index c66e92b79..990067e3a 100755 --- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.infra.service.db; +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.mybatis.core.type.EncryptTypeHandler; import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO; @@ -8,8 +10,10 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO; import cn.iocoder.yudao.module.infra.dal.mysql.db.DataSourceConfigMapper; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; import org.jasypt.encryption.StringEncryptor; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; +import org.mockito.stubbing.Answer; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; @@ -21,7 +25,10 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_EXISTS; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; /** * {@link DataSourceConfigServiceImpl} 的单元测试类 @@ -43,13 +50,20 @@ public class DataSourceConfigServiceImplTest extends BaseDbUnitTest { @MockBean private DynamicDataSourceProperties dynamicDataSourceProperties; + @BeforeEach + public void setUp() { + // mock 一个空实现的 StringEncryptor,避免 EncryptTypeHandler 报错 + ReflectUtil.setFieldValue(EncryptTypeHandler.class, "encryptor", stringEncryptor); + when(stringEncryptor.encrypt(anyString())).then((Answer) invocation -> invocation.getArgument(0)); + when(stringEncryptor.decrypt(anyString())).then((Answer) invocation -> invocation.getArgument(0)); + } + @Test public void testCreateDataSourceConfig_success() { try (MockedStatic databaseUtilsMock = mockStatic(JdbcUtils.class)) { // 准备参数 DataSourceConfigCreateReqVO reqVO = randomPojo(DataSourceConfigCreateReqVO.class); // mock 方法 - when(stringEncryptor.encrypt(eq(reqVO.getPassword()))).thenReturn("123456"); databaseUtilsMock.when(() -> JdbcUtils.isConnectionOK(eq(reqVO.getUrl()), eq(reqVO.getUsername()), eq(reqVO.getPassword()))).thenReturn(true); @@ -59,8 +73,7 @@ public class DataSourceConfigServiceImplTest extends BaseDbUnitTest { assertNotNull(dataSourceConfigId); // 校验记录的属性是否正确 DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(dataSourceConfigId); - assertPojoEquals(reqVO, dataSourceConfig, "password"); - assertEquals("123456", dataSourceConfig.getPassword()); + assertPojoEquals(reqVO, dataSourceConfig); } } @@ -75,7 +88,7 @@ public class DataSourceConfigServiceImplTest extends BaseDbUnitTest { o.setId(dbDataSourceConfig.getId()); // 设置更新的 ID }); // mock 方法 - when(stringEncryptor.encrypt(eq(reqVO.getPassword()))).thenReturn("123456"); +// when(stringEncryptor.encrypt(eq(reqVO.getPassword()))).thenReturn("123456"); databaseUtilsMock.when(() -> JdbcUtils.isConnectionOK(eq(reqVO.getUrl()), eq(reqVO.getUsername()), eq(reqVO.getPassword()))).thenReturn(true); @@ -83,8 +96,7 @@ public class DataSourceConfigServiceImplTest extends BaseDbUnitTest { dataSourceConfigService.updateDataSourceConfig(reqVO); // 校验是否更新正确 DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(reqVO.getId()); // 获取最新的 - assertPojoEquals(reqVO, dataSourceConfig, "password"); - assertEquals("123456", dataSourceConfig.getPassword()); + assertPojoEquals(reqVO, dataSourceConfig); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java index 0f56bfb3b..37dc57968 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.framework.mybatis.core.type.StringLiSTTypeHandler; +import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -46,7 +46,7 @@ public class SensitiveWordDO extends BaseDO { * 例如说,tag 有短信、论坛两种,敏感词 "推广" 在短信下是敏感词,在论坛下不是敏感词。 * 此时,我们会存储一条敏感词记录,它的 name 为"推广",tag 为短信。 */ - @TableField(typeHandler = StringLiSTTypeHandler.class) + @TableField(typeHandler = StringListTypeHandler.class) private List tags; /** * 状态 diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/tip/core/TipApplicationRunner.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/tip/core/TipApplicationRunner.java index 469256f6d..18460f99e 100644 --- a/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/tip/core/TipApplicationRunner.java +++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/tip/core/TipApplicationRunner.java @@ -23,7 +23,7 @@ public class TipApplicationRunner implements ApplicationRunner { "项目启动成功!\n\t" + "接口文档: \t{} \n\t" + "开发文档: \t{} \n\t" + - "视频教程: \t{} \n" + + "视频教程: \t{} \n\t" + "源码解析: \t{} \n" + "----------------------------------------------------------", "https://mtw.so/6w48hX",