使用TypeHandler对数据库敏感信息加解密

MyBatis TypeHandler

本篇文章是对这篇文章的补充与归纳总结

背景

在开发中,我们针对敏感信息需要做加密存储。比如:密码、手机号、邮箱、地址等。在程序里还需要对这些加密过的信息做处理(查询、更新等),所以需要一种很便捷的方式。

思路

在使用MyBatis时,LocalDateTime/String等类型会被自动转换为数据库对应的datetime/timestamp/varchar类型;并且使用的是TypeHandler。官网对TypeHandler的定义如下:

Whenever MyBatis sets a parameter on a PreparedStatement or retrieves a value from a ResultSet, a TypeHandler is used to retrieve the value in a means appropriate to the Java type. The following table describes the default TypeHandlers.

那我们是否也可以拓展TypeHandler完成敏感信息的加解密。

整理清楚上面关系,我们接下来要完成以下步骤:

  • 编写加解密类
  • 编写加密TypeHandler,并使用加解密类
  • 注册TypeHandler
  • 针对需要加密的字段使用TypeHandler

实现

1. 编写加解密类

略。可以针对不同的场景写不同的加解密类(手机号:数字加解密; 密码:字符串加解密; 地址: 带搜索的字符串加解密等)。

2. 编写TypeHandler

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;


public class CryptFullStringTypeHandler extends BaseTypeHandler<String> {
	private final CryptField<String> cryptField;

	public CryptFullStringTypeHandler() {
		cryptField = new CryptFull();
	}

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
		ps.setString(i, cryptField.encrypt(parameter));
	}

	@Override
	public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
		return cryptField.decrypt(rs.getString(columnName));
	}

	@Override
	public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		return cryptField.decrypt(rs.getString(columnIndex));
	}

	@Override
	public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		return cryptField.decrypt(cs.getString(columnIndex));
	}

}

3.注册TypeHandler

在mybatis里,注册TypeHandler有2种方式,一种根据class注册,另一种是根据package扫描。这里我使用第二种。

4.使用TypeHandler

4.1 MyBatis使用加密TypeHandler

在xxx.xml文件里,指定typeHandler。例如:

    <result column="NAME" jdbcType="VARCHAR" property="name" typeHandler="com.demo.mybatis.type.CryptSimpleStringTypeHandler" />

4.2 MyBatis Plus使用加密TypeHandler

在entity class类里的字段添加typeHandler注解属性。例如:

@TableField(value = "NAME", typeHandler = com.demo.mybatis.type.CryptSimpleStringTypeHandler.class)
private String name;

拓展

启动单元测试跑一下,通过此种方法就可以完成数据库敏感字段的自动加解密了。如果对加密算法有特殊要求,比如:对数字的加解密、对数字加解密之后要支持搜索、对字符串的加解密、对字符串加解密要支持搜索、要控制加密后的最大长度、撒盐等等,都可以在加解密算法上做拓展,这里不展开讲述。

总结:遇到问题多思考,多看看别人是怎么做的,了解框架的实现原理,说不定其中就有某些可以让我们借助使用。