上一篇,我用的自定义注解+AOP的方式,实现敏感字段的加解密,这一篇换个方案,这个方案相比一个方案,节省了一部分的性能开销
第一步:新建自定义注解
/**
* 敏感信息类注解
*/
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableSensitive {
boolean value() default true;
}
/**
* 敏感字段注解
*/
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveFiled {
String value() default "";
}
第二步:创建加密实现类
@Component
@Intercepts({
//@Signature注解定义拦截器的实际类型
@Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class)
})
public class EncryptInterceptor implements Interceptor {
@Resource
private SensitiveInfoService sensitiveInfoService;
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 取出请求参数
ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
Object parameterObject = parameterHandler.getParameterObject();
// 如果参数不为空,并且是MapperMethod.ParamMap类型
if (parameterObject instanceof MapperMethod.ParamMap) {
Map<String, ?> paramMap = (MapperMethod.ParamMap) parameterObject;
// 遍历请求参数,对敏感信息字段加密
paramMap.forEach((k, v) -> {
// 参数不为空,并且不是mybatis默认参数名
if (null != paramMap.get(k)) {
Object param = paramMap.get(k);
EnableSensitive enableSensitive = AnnotationUtils.findAnnotation(param.getClass(), EnableSensitive.class);
if (null != enableSensitive && enableSensitive.value()) {
// 对敏感信息类中的敏感信息字段加密
sensitiveInfoService.encrypt(param);
}
}
});
}
return invocation.proceed();
}
/**
* 加入此拦截器到拦截器链
*/
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
}
代码注释:
这段代码的功能是实现一个名为EncryptInterceptor的类,用作MyBatis的拦截器,主要对数据库操作中的敏感信息字段进行加密处理。具体功能如下:
- 依赖注入:通过@Resource注解,注入SensitiveInfoService服务,用于敏感信息的加密处理。
- 拦截器实现:实现Interceptor接口,对指定的方法进行拦截。此处拦截的是ParameterHandler类的setParameters方法,该方法负责设置PreparedStatement的参数。
- 参数获取与判断:在intercept方法中,获取ParameterHandler的参数对象。如果参数对象不为空且为MapperMethod.ParamMap类型(即Mapper接口方法的参数被封装成Map形式),则进行后续处理。
- 敏感信息加密:遍历参数Map,对每个非空参数值,检查其类上是否标注了@EnableSensitive注解且值为true。如果满足条件,调用sensitiveInfoService的encrypt方法对该参数的敏感字段进行加密。
- 执行流程控制:完成加密处理后,通过invocation.proceed()继续执行被拦截的方法,即ParameterHandler的setParameters方法。
- 插件机制:通过plugin方法,利用MyBatis的插件机制,将此拦截器加入到MyBatis的拦截器链中,从而对指定的目标对象进行增强处理。
综上所述,EncryptInterceptor的主要作用是在MyBatis执行SQL之前,拦截并加密Mapper方法中的敏感信息字段,确保敏感数据的安全性。
第三步:创建解密实现类
@Component
@Intercepts({
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class DecryptInterceptor implements Interceptor {
@Resource
private SensitiveInfoService sensitiveInfoService;
@Override
public Object intercept(Invocation invocation) throws Throwable {
//取出查询的结果
Object resultObject = invocation.proceed();
if (null != resultObject) {
// 校验是否需要解密,并对敏感信息进行解密
sensitiveInfoService.decrypt(resultObject);
}
return resultObject;
}
/**
* 加入此拦截器到拦截器链
*/
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
}
代码注释:
这段代码定义了一个名为DecryptInterceptor的拦截器类,用于在查询数据库后对结果进行解密。该拦截器通过@Component和@Intercepts注解标记,指定了它将拦截ResultSetHandler类中的handleResultSets方法,该方法接受一个Statement类参数。
主要功能包括:
- 拦截查询结果:在intercept方法中,拦截器取出查询的结果对象。
- 解密敏感信息:利用注入的SensitiveInfoService服务,检查查询结果是否需要解密,并对包含的敏感信息执行解密操作。
- 返回解密后的结果:最后,将处理后的结果返回。
此外,plugin方法用于将此拦截器加入到拦截器链中,使用Plugin.wrap方法包装目标对象。
示例: