注解切面实现字段存入数据库自动加解密

首先创建两个注解,一个是写在方法上的注解,表明哪些方法是需要加解密操作的,另一个注解是写在实体类上的字段上(自定义的vo和dto也可以加上注释),表明这个实体类的这个字段需要加解密操作。

1.方法注解

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface EnCodeMethod {
}

2.字段注解

@Inherited
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Order(Ordered.HIGHEST_PRECEDENCE)
public @interface EnCodeField {
}

然后创建字段加解密切面

@Order(Ordered.HIGHEST_PRECEDENCE)
@Aspect
@Component
public class asdasd {
    Logger log = LoggerFactory.getLogger(this.getClass());


    @Pointcut("@annotation(com.ny.common.annotation.EnCodeMethod)")
    public void annotationPointCut() {
    }

    @Around("annotationPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Exception {
        Object responseObj = new Object();
        try {
            Object requestObj = joinPoint.getArgs()[0];
            handleEncrypt(requestObj);
            responseObj = joinPoint.proceed();
            handleDecrypt(responseObj);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            log.error("SecureFieldAop处理出现异常{}", e);
            throw new RuntimeException("加解密服务异常");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            log.error("SecureFieldAop处理出现异常{}", throwable);
            throw new RuntimeException("加解密服务异常");
        }
        return responseObj;
    }

    /**
     * 处理加密
     *
     * @param requestObj
     */
    private void handleEncrypt(Object requestObj) throws Exception {
        // 加密用的字段,是否需要看实际业务需求
        Integer decryptIndex = 1;
        if (Objects.isNull(requestObj)) {
            return;
        }
        //获取传入参数的字段list
        Field[] fields = getAllField(requestObj);
        for (Field field : fields) {
            //获取参数中加过注解的字段
            boolean hasSecureField = field.isAnnotationPresent(EnCodeField.class);
            //判断有没有加过注解的字段
            if (hasSecureField) {
                field.setAccessible(true);
                String plaintextValue;
                String encryptValue = null;
                if (field.get(requestObj) != null) {

                    plaintextValue = (String) field.get(requestObj);
                    //如果有,进行加密操作,然后替换成加密之后的值
                    encryptValue = encyptEcb(decryptIndex, plaintextValue);
                    field.set(requestObj, encryptValue);

                }
            }
        }
    }


    /**
     * 处理解密
     *
     * @param responseObj
     */
    private Object handleDecrypt(Object responseObj) throws Exception {

        Integer decryptIndex = 1;
        if (Objects.isNull(responseObj)) {
            return null;
        }
        //获取返回值的字段
        Field[] fields = getAllField(responseObj);
        for (Field field : fields) {
            //获取加了注解的字段
            boolean hasSecureField = field.isAnnotationPresent(EnCodeField.class);
            if (hasSecureField) {
                field.setAccessible(true);

                String encryptValue = (String) field.get(responseObj);
                //加密字段可能为空,先做判断
                if (!EmptyUtil.isEmpty(encryptValue)) {
                    //解密
                    String plaintextValue = decryptEcb(decryptIndex, encryptValue);
                    field.set(responseObj, plaintextValue);
                }

            }

        }
        return responseObj;
    }

    private Field[] getAllField(Object obj) {
        ArrayList fieldList = new ArrayList();

        Field[] dFields = obj.getClass().getDeclaredFields();

        if (null != dFields && dFields.length > 0) {
            fieldList.addAll(Arrays.asList(dFields));

        }
        //因为业务需求中定义的类可能会直接基础实体类,所以需要把父级中的字段也加上
        Class superClass = obj.getClass().getSuperclass();
        if (superClass != Object.class) {
            Field[] superFields = superClass.getDeclaredFields();

            if (null != superFields && superFields.length > 0) {
                for (Field field : superFields) {
                    fieldList.add(field);
                }
            }
        }
        Field[] result = new Field[fieldList.size()];
        fieldList.toArray(result);

        return result;
    }


    //加密操作,根据实际需求
    public String encyptEcb(int keySize, String paramStr) throws Exception {
        // 加密操作 TODO
        // 根据实际需求加密字段后返回加密字段
        return paramStr;
    }


    //解密操作,根据实际需求
    public String decryptEcb(int keySize, String paramStr) throws Exception {
        // 解密操作 TODO
        // 根据实际需求解密字段后返回解密字段
        return paramStr;
    }
    
}

然后实际的业务中在需要的加解密方法体上加上@EnCodeMethod,需要加解密的方法体上加上@EnCodeField即可。

这个切面的操作是把requestObj(传入参数)加密,然后responseObj(返回参数)解密,是一体的。


版权声明:本文为weixin_44229535原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。