1 问题背景
在数据库存储人员的信息时,有一些信息是敏感数据,如身份证号、出生地等。为了防止信息泄漏,这些信息不允许直接在数据库中查看,此时就需要对这些字段进行加密存储,但在页面查看的仍旧是解密后的数据。这里就涉及到加解密的问题,有两种解决方案。
2 解决方案
2.1 使用数据库加密算法
通过数据库自带的加密算法,在sql里直接使用算法加解密,这种有较多缺点,不推荐使用。
- 写法繁琐,不易开发维护
- 适配多种数据库时,算法难以统一,工作量也剧增
2.2 使用mybatis的自定义参数类型转换器
通过自定义Java类型和类型转换器,并在mapper.xml里标注类型,通过mybatis进行加解密。
- 加密算法可自由选择
- 开发维护比较简单方便
- 不存在适配多种数据库的问题
3 一般web项目使用
3.1 创建自定义Java类型
创建一个空白类,在mapper.xml文件查询和新增修改时标注说明,表示需要mybatis进行相关类型转换。
@Alias("SecretField")
public class SecretField {
}
3.2 自定义类的转换处理器
这里使用国密SM4进行加解密,当然算法可自由选择别的如AES等。
@MappedTypes注解映射刚才的自定义Java类
@MappedTypes(SecretField.class)
public class SecretFieldTypeHandler extends BaseTypeHandler<String> {
private static final Logger log = LoggerFactory.getLogger(SecretFieldTypeHandler.class);
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
try {
if (StringUtils.hasText(parameter)) {
String encryptStr = Sm4Util.encryptData_ECB(parameter);
ps.setString(i, encryptStr);
}
} catch (Exception e) {
ps.setString(i, parameter);
log.error("mybatis加密参数异常,i:{},parameter:{}", i, parameter);
}
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
String columnValue = rs.getString(columnName);
try {
if (StringUtils.hasText(columnValue)) {
columnValue = Sm4Util.decryptData_ECB(columnValue);
}
} catch (Exception e) {
log.error("mybatis解密参数异常,columnName:{}, columnValue:{}", columnName, columnValue);
}
return columnValue;
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return null;
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return null;
}
}
3.3 配置自定义类型和类型转换器
这一步也可使用相关注解完成。
配置文件为mybatis的配置文件,如mybatis-config.xml。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE configuration PUBLIC "-//mybaties.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
</settings>
<typeAliases>
<typeAlias type="com.banxian.mybatis.alias.SecretField" alias="SecretField"/>
</typeAliases>
<typeHandlers>
<typeHandler handler="com.banxian.mybatis.typehandler.SecretFieldTypeHandler" />
</typeHandlers>
</configuration>
3.4 查询使用
查询返回需通过resultMap映射,在加密字段进行javaType指明需要的类型转换器。
另外如果旧代码中结果集大量直接使用map返回,时间紧张的情况下,则可考虑写一个工具类,在service里调用进行手动解密,没得办法呀!。
<resultMap id="BaseResultMap" type="User">
<result column="sfz" property="sfz" javaType="SecretField"/>
</resultMap>
3.5 新增修改使用
在设置相关参数值时,也就是在#{}里,使用javaType指明需要的类型转换器。
insert into ... values(...
<if test="sfz!= null">
#{sfz,jdbcType=VARCHAR,javaType=SecretField},
</if>
)
4. springboot项目使用
- 自定义类型和类型转换器代码和上面一样,这里不在赘述。
- 项目使用了mybatis-plus插件。
4.1 配置自定义类型和类型转换器
在项目配置文件里application.yml里加上配置type-handlers-package
和 type-aliases-package:
分别指出你的类型转换器所在包名和自定义类所在包名。
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-not-delete-value: "0"
logic-delete-value: "1"
mapper-locations: "classpath*:/mapper*.xml"
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
type-handlers-package: com.banxian.mybatis.typehandler
type-aliases-package: com.banxian.mybatis.alias
4.2 mybatis-plus的使用
当然上面web项目的查询、新增和修改使用方法这里也是可以正常使用的
1)在实体类上使用注解
@TableName(autoResultMap = true)
2)在加密字段上指明类型
@TableField(value = "sfz", typeHandler = SecretFieldTypeHandler.class)
@Data
@TableName(autoResultMap = true)
public class User implements Serializable {
private static final long serialVersionUID = 4344848828462926573L;
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Integer id;
private String userName;
@TableLogic
private String deleted;
private String valid;
@TableField(value = "create_at", fill = FieldFill.INSERT)
private LocalDateTime createAt;
@TableField(value = "update_at", fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateAt;
@TableField(value = "sfz", typeHandler = SecretFieldTypeHandler.class)
private String sfz;
}
以上就是mybatis自定义参数类型转换器数据库字段加密脱敏的详细内容,更多关于mybatis数据库字段加密脱敏的资料请关注编程网其它相关文章!