由于业务需求,需对数据库中的敏感数据进行加密,而在业务代码中进行加解密比较繁琐,因此可以使用注解字段的方式决定字段的加解密.
一.新增注解
1.由于不可能每个表数据都进行加解密,此注解用于类上标记类中有加解密字段.
/** * <pre> * * 该annotation 标记在类上面表示该类有解密和加密的字段 * </pre> */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Inherited public @interface SecureFlag { }
2.作用于字段和参数上的加解密字段
/** * <pre> * * 字段加密和解密(放在实体类上配合@{@link SecureFlag}使用) * (或放在方法参数前使用) * * 标记参数或者字段 * * </pre> */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.PARAMETER}) public @interface Secure { }
二,aop实现注解拦截和加解密实现
可以根据业务进行自己调整,下面只是一个思路
/** * 加解密切面 * */ @Aspect @Slf4j @Configuration public class DesAndEncAspect { //切所有mapper @Pointcut("execution(public * xx.xx.mapper.*.*(..))") public void pointcut() { } @Around("pointcut()") public Object aroundReturning(ProceedingJoinPoint joinPoint) throws Throwable { //获取方法参数 Object[] args = joinPoint.getArgs(); Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); //获取dao层接口参数注解 start Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (int i = 0; i < parameterAnnotations.length; i++) { for (Annotation annotation : parameterAnnotations[i]) { //方法参数包含注解,进行加密 if (annotation instanceof Secure) { args[i] = CryptPojoUtils.encryptObject(args[i]); } } } //获取dao层接口参数注解 end //获取参数实体类注解 CryptPojoUtils.encryptFields(args); //执行方法 Object proceed = joinPoint.proceed(args); if (null == proceed) { return null; } //解密 CryptPojoUtils.decryptFieldOrList(proceed); return proceed; } }
CryptPojoUtils的代码,AESUtil的方法需自己实现.
/** * 加解密工具类 **/ public class CryptPojoUtils { private final static String KEY = "XXXXXX"; /** * 对含注解字段解密 */ public static <T> void decryptFieldOrList(T t) { if (null == t) { return; } if (t instanceof List) { List values = (List) t; for (Object object : values) { CryptPojoUtils.decryptField(object); } } else { CryptPojoUtils.decryptField(t); } } /** * 对含注解字段解密 */ private static <T> void decryptField(T t) { SecureFlag annotation = t.getClass().getAnnotation(SecureFlag.class); if (null == annotation) { return; } Field[] declaredFields = t.getClass().getDeclaredFields(); try { if (declaredFields != null && declaredFields.length > 0) { for (Field field : declaredFields) { if (field.isAnnotationPresent(Secure.class)) && field.getType().toString().endsWith("String")) { field.setAccessible(true); String fieldValue = (String) field.get(t); if (StringUtils.isNotEmpty(fieldValue)) { field.set(t, AESUtil.aesDecrypt(fieldValue, KEY)); } } } } } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * 对含注解字段加密 */ private static <T> void encryptField(T t) { if (null == t) { return; } SecureFlag annotation = t.getClass().getAnnotation(SecureFlag.class); if (null == annotation) { return; } Field[] declaredFields = t.getClass().getDeclaredFields(); try { if (declaredFields != null && declaredFields.length > 0) { for (Field field : declaredFields) { if (field.isAnnotationPresent(Secure.class)) && field.getType().toString().endsWith("String")) { field.setAccessible(true); String fieldValue = (String) field.get(t); if (StringUtils.isNotEmpty(fieldValue)) { field.set(t, AESUtil.aesEncrypt(fieldValue, KEY)); } } } } } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * 对含注解字段加密 */ public static <T> void encryptFields(T[] objects) { for (Object obj : objects) { encryptField(obj); } } public static String encryptObject(Object object) { if (null == object) { return null; } return AESUtil.aesEncrypt(String.valueOf(object), KEY); } }