最近又遇到了脱敏数据查询相关的问题,常规的脱敏数据比如用户身份证将中间位数抹去后加入数据库,那么查询时需要手动调用就比较麻烦,不过可以使用自定义注解,利用AOP解析后在切面将数据加密再作为参数注入运行,实现非入侵的脱敏数据明文查询。简单记录一下。
用户身份证脱敏,保留前四位和后八位,其余转换为×符号存入数据库。利用aop在方法执行的切面将注解修饰的方法中对应的参数进行加密后注入,就能实现脱敏数据的明文搜索,而不用手动调工具类了。
简单的用户信息,code为身份证。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String code;
private String name;
private byte sex;
}
简单的搜索接口。
@Mapper
public interface UserMapper {
@Select("select * from user where code = #{code}")
public User findUserByCode(String code);
}
将加密类型也作为参数,适应不同情况。
public class EncryptionUtil {
public final static String SELF_CODE = "self_code";
// 加密
public static String encrypt(String str, String type){
if (SELF_CODE.equals(type)) {// 身份证前四位加上后六位
return str.substring(0, 4) + "xxxxxxxx" + str.substring(str.length() - 6);
}
return null;
}
}
@Encrypt
注解,包含两个成员,indexes
数组存放需要加密的参数序号,types
存放加密类型。
// 自动加密注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypt {
// 记录需要加密的参数位置
int[] indexes();
// 记录加密对像的type
String[] types();
}
关键逻辑类,使用around
方法和ProceedingJoinPoint
对象将获取对应切面方法的注解和参数信息,对参数进行加密处理后注入。
@Component
@Aspect
public class EncryptAspect {
@Pointcut("execution(* com.huiluczP.controller.UserController.*(..)) && @annotation(com.huiluczP.annotation.Encrypt)")
private void point() {
}
@Around("point()")
// 环绕aop,获取切面方法对应的annotation
private Object around(ProceedingJoinPoint pjp) throws Throwable {
// 得到方法执行所需的参数
Object[] args = pjp.getArgs();
Encrypt encryptParam = ((MethodSignature) pjp.getSignature()).getMethod().getAnnotation(Encrypt.class);
// 获取需要加密的参数位置和加密类型
int[] indexes = encryptParam.indexes();
String[] types = encryptParam.types();
// 对参数进行处理
for(int i=0;i<indexes.length;i++){
int index = indexes[i];
args[index] = EncryptionUtil.encrypt((String)args[index], types[i]);
}
return pjp.proceed(args);
}
}
这边利用execution(* com.huiluczP.controller.UserController.*(..)) && @annotation(com.huiluczP.annotation.Encrypt)
将UserController中持有@Encrypt
注解的所有方法都归入切面。
传入明文对象进行脱敏数据的查询。在注解中定义了加密参数位置和类型。
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
UserMapper userMapper;
@RequestMapping("/findByCode")
@ResponseBody
// 自动加密注解
@Encrypt(indexes = {0}, types = {EncryptionUtil.SELF_CODE})
public String findUser(String code){
User user = userMapper.findUserByCode(code);
return JSONObject.toJSONString(user);
}
}
成功进行了查询。
简单的Aop应用,来解决脱敏数据明文查询的代码冗余问题,面向切面确实蛮方便的,就是切面定义表达式比较难写。感兴趣就看看吧。