数据库敏感字段加解密
为了保护数据库敏感字段数据安全,有时候我们需要将敏感数据加密入库,查询时再解密成明文。我们可以利用Mybatis自定义TypeHandler来处理,下面我们来具体实现一下。
定义KeyCenterUtils加解密工具类
import org.springframework.stereotype.Service;
import java.util.Base64;
@Service
public class KeyCenterUtils {
public String encrypt(String src) {
try {
String result = Base64.getEncoder().encodeToString(src.getBytes("UTF-8"));
return result;
} catch (Exception e) {
throw new RuntimeException("encrypt fail!", e);
}
}
public String decrypt(String src) {
try {
byte[] asBytes = Base64.getDecoder().decode(src);
String result = new String(asBytes, "UTF-8");
return result;
} catch (Exception e) {
throw new RuntimeException("decrypt fail!", e);
}
}
}
自定义Handler类实现数据库字段加解密
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mk.util.KeyCenterUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CustomTypeHandler<T> extends BaseTypeHandler<T> {
@Autowired
private KeyCenterUtils keyCenterUtils;
public CustomTypeHandler() {
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, this.keyCenterUtils.encrypt((String)parameter));
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
String columnValue = rs.getString(columnName);
//有一些可能是空字符
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T)this.keyCenterUtils.decrypt(columnValue);
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String columnValue = rs.getString(columnIndex);
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T)this.keyCenterUtils.decrypt(columnValue);
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String columnValue = cs.getString(columnIndex);
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T)this.keyCenterUtils.decrypt(columnValue);
}
}
因为我用的是Mybatis-Plus,所以可以使用Mybatis-Plus的@TableField
的注解通过typeHandler
属性指定上面自定义的Handler即可。
实体类添加注解
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "lemon_user", autoResultMap = true)
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
@TableField(typeHandler = CustomTypeHandler.class)
private String password;
private String salt;
}
注意:上面的@TableName
注解设置了autoResultMap = true
的属性值,这样通过Mybatis-Plus的BaseMapper查询出来的数据才会将加密字段进行解密,默认不生效。
如果不是Mybatis-Plus的 BaseMapper内部的方法,则需要我们在查询时在resultMap
的属性中指定我们自定义的typeHandler,如下:
<resultMap id="baseResultMap" type="com.mk.entity.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password" typeHandler="com.mk.handler.CustomTypeHandler"/>
</resultMap>
<select id="getUserByName" resultMap="baseResultMap">
select * from lemon_user where username = #{username}
</select>