xiongzhu 2 năm trước cách đây
mục cha
commit
15c9dac588
37 tập tin đã thay đổi với 1460 bổ sung1 xóa
  1. 225 0
      src/main/java/cn/licoy/encryptbody/advice/DecryptRequestBodyAdvice.java
  2. 234 0
      src/main/java/cn/licoy/encryptbody/advice/EncryptResponseBodyAdvice.java
  3. 230 0
      src/main/java/cn/licoy/encryptbody/annotation/EnableEncryptBody.java
  4. 17 0
      src/main/java/cn/licoy/encryptbody/annotation/decrypt/AESDecryptBody.java
  5. 17 0
      src/main/java/cn/licoy/encryptbody/annotation/decrypt/DESDecryptBody.java
  6. 22 0
      src/main/java/cn/licoy/encryptbody/annotation/decrypt/DecryptBody.java
  7. 14 0
      src/main/java/cn/licoy/encryptbody/annotation/decrypt/RSADecryptBody.java
  8. 17 0
      src/main/java/cn/licoy/encryptbody/annotation/encrypt/AESEncryptBody.java
  9. 17 0
      src/main/java/cn/licoy/encryptbody/annotation/encrypt/DESEncryptBody.java
  10. 25 0
      src/main/java/cn/licoy/encryptbody/annotation/encrypt/EncryptBody.java
  11. 14 0
      src/main/java/cn/licoy/encryptbody/annotation/encrypt/MD5EncryptBody.java
  12. 14 0
      src/main/java/cn/licoy/encryptbody/annotation/encrypt/RSAEncryptBody.java
  13. 19 0
      src/main/java/cn/licoy/encryptbody/annotation/encrypt/SHAEncryptBody.java
  14. 26 0
      src/main/java/cn/licoy/encryptbody/bean/DecryptAnnotationInfoBean.java
  15. 33 0
      src/main/java/cn/licoy/encryptbody/bean/DecryptHttpInputMessage.java
  16. 27 0
      src/main/java/cn/licoy/encryptbody/bean/EncryptAnnotationInfoBean.java
  17. 32 0
      src/main/java/cn/licoy/encryptbody/config/EncryptBodyConfig.java
  18. 51 0
      src/main/java/cn/licoy/encryptbody/config/HttpConverterConfig.java
  19. 12 0
      src/main/java/cn/licoy/encryptbody/enums/DecryptBodyMethod.java
  20. 12 0
      src/main/java/cn/licoy/encryptbody/enums/EncryptBodyMethod.java
  21. 22 0
      src/main/java/cn/licoy/encryptbody/enums/SHAEncryptType.java
  22. 17 0
      src/main/java/cn/licoy/encryptbody/exception/DecryptBodyFailException.java
  23. 17 0
      src/main/java/cn/licoy/encryptbody/exception/DecryptMethodNotFoundException.java
  24. 17 0
      src/main/java/cn/licoy/encryptbody/exception/EncryptBodyFailException.java
  25. 17 0
      src/main/java/cn/licoy/encryptbody/exception/EncryptMethodNotFoundException.java
  26. 17 0
      src/main/java/cn/licoy/encryptbody/exception/KeyNotConfiguredException.java
  27. 64 0
      src/main/java/cn/licoy/encryptbody/util/AESEncryptUtil.java
  28. 20 0
      src/main/java/cn/licoy/encryptbody/util/CheckUtils.java
  29. 65 0
      src/main/java/cn/licoy/encryptbody/util/DESEncryptUtil.java
  30. 44 0
      src/main/java/cn/licoy/encryptbody/util/Hex2Util.java
  31. 34 0
      src/main/java/cn/licoy/encryptbody/util/MD5EncryptUtil.java
  32. 44 0
      src/main/java/cn/licoy/encryptbody/util/SHAEncryptUtil.java
  33. 14 0
      src/main/java/cn/licoy/encryptbody/util/StringUtils.java
  34. 2 0
      src/main/java/com/izouma/nineth/Application.java
  35. 1 1
      src/main/java/com/izouma/nineth/config/WebMvcConfig.java
  36. 3 0
      src/main/java/com/izouma/nineth/web/AssetController.java
  37. 4 0
      src/main/resources/application.yaml

+ 225 - 0
src/main/java/cn/licoy/encryptbody/advice/DecryptRequestBodyAdvice.java

@@ -0,0 +1,225 @@
+package cn.licoy.encryptbody.advice;
+
+import cn.licoy.encryptbody.annotation.decrypt.AESDecryptBody;
+import cn.licoy.encryptbody.annotation.decrypt.DESDecryptBody;
+import cn.licoy.encryptbody.annotation.decrypt.DecryptBody;
+import cn.licoy.encryptbody.annotation.decrypt.RSADecryptBody;
+import cn.licoy.encryptbody.annotation.encrypt.*;
+import cn.licoy.encryptbody.bean.DecryptAnnotationInfoBean;
+import cn.licoy.encryptbody.bean.DecryptHttpInputMessage;
+import cn.licoy.encryptbody.config.EncryptBodyConfig;
+import cn.licoy.encryptbody.enums.DecryptBodyMethod;
+import cn.licoy.encryptbody.exception.DecryptBodyFailException;
+import cn.licoy.encryptbody.exception.DecryptMethodNotFoundException;
+import cn.licoy.encryptbody.util.AESEncryptUtil;
+import cn.licoy.encryptbody.util.CheckUtils;
+import cn.licoy.encryptbody.util.DESEncryptUtil;
+import cn.licoy.encryptbody.util.StringUtils;
+import jodd.util.ReflectUtil;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 请求数据的加密信息解密处理<br>
+ * 本类只对控制器参数中含有<strong>{@link org.springframework.web.bind.annotation.RequestBody}</strong>
+ * 以及package为<strong>{@link cn.licoy.encryptbody.annotation.decrypt}</strong>下的注解有效
+ *
+ * @author licoy.cn
+ * @version 2018/9/7
+ * @see RequestBodyAdvice
+ */
+@Order(1)
+@ControllerAdvice
+@Slf4j
+public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
+
+    @Autowired
+    private EncryptBodyConfig config;
+
+    @Override
+    public boolean supports(MethodParameter methodParameter, @Nonnull Type targetType, @Nonnull Class<? extends HttpMessageConverter<?>> converterType) {
+        Annotation[] annotations = methodParameter.getDeclaringClass().getAnnotations();
+        if (annotations != null && annotations.length > 0) {
+            for (Annotation annotation : annotations) {
+                if (annotation instanceof DecryptBody ||
+                        annotation instanceof AESDecryptBody ||
+                        annotation instanceof DESDecryptBody ||
+                        annotation instanceof RSADecryptBody) {
+                    return true;
+                }
+            }
+        }
+        if (Arrays.stream(ReflectUtil.getSuperclasses(methodParameter.getDeclaringClass()))
+                .flatMap(clazz -> Arrays.stream(clazz.getAnnotations()))
+                .anyMatch(annotation -> annotation instanceof DecryptBody ||
+                        annotation instanceof AESDecryptBody ||
+                        annotation instanceof DESDecryptBody ||
+                        annotation instanceof RSADecryptBody)) {
+            return true;
+        }
+        return methodParameter.getMethod() != null &&
+                (methodParameter.getMethod().isAnnotationPresent(DecryptBody.class) ||
+                        methodParameter.getMethod().isAnnotationPresent(AESDecryptBody.class) ||
+                        methodParameter.getMethod().isAnnotationPresent(DESDecryptBody.class) ||
+                        methodParameter.getMethod().isAnnotationPresent(RSADecryptBody.class));
+    }
+
+    @Override
+    public Object handleEmptyBody(Object body, @Nonnull HttpInputMessage inputMessage,
+                                  @Nonnull MethodParameter parameter, @Nonnull Type targetType,
+                                  @Nonnull Class<? extends HttpMessageConverter<?>> converterType) {
+        return body;
+    }
+
+    @SneakyThrows
+    @Override
+    @Nonnull
+    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, @Nonnull MethodParameter parameter,
+                                           @Nonnull Type targetType,
+                                           @Nonnull Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
+        inputMessage.getBody();
+        String body;
+        try {
+            body = IOUtils.toString(inputMessage.getBody(), config.getEncoding());
+        } catch (Exception e) {
+            throw new DecryptBodyFailException("Unable to get request body data," +
+                    " please check if the sending data body or request method is in compliance with the specification." +
+                    " (无法获取请求正文数据,请检查发送数据体或请求方法是否符合规范。)");
+        }
+        if (body == null || StringUtils.isNullOrEmpty(body)) {
+            throw new DecryptBodyFailException("The request body is NULL or an empty string, so the decryption failed." +
+                    " (请求正文为NULL或为空字符串,因此解密失败。)");
+        }
+        String decryptBody = null;
+        DecryptAnnotationInfoBean methodAnnotation = this.getMethodAnnotation(parameter);
+        if (methodAnnotation != null) {
+            decryptBody = switchDecrypt(body, methodAnnotation);
+        } else {
+            DecryptAnnotationInfoBean classAnnotation = this.getClassAnnotation(parameter.getDeclaringClass());
+            if (classAnnotation != null) {
+                decryptBody = switchDecrypt(body, classAnnotation);
+            }
+        }
+        if (decryptBody == null) {
+            throw new DecryptBodyFailException("Decryption error, " +
+                    "please check if the selected source data is encrypted correctly." +
+                    " (解密错误,请检查选择的源数据的加密方式是否正确。)");
+        }
+        try {
+            InputStream inputStream = IOUtils.toInputStream(decryptBody, config.getEncoding());
+            return new DecryptHttpInputMessage(inputStream, inputMessage.getHeaders());
+        } catch (Exception e) {
+            throw new DecryptBodyFailException("The string is converted to a stream format exception." +
+                    " Please check if the format such as encoding is correct." +
+                    " (字符串转换成流格式异常,请检查编码等格式是否正确。)");
+        }
+    }
+
+    @Override
+    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
+        return body;
+    }
+
+    /**
+     * 获取方法控制器上的加密注解信息
+     *
+     * @param methodParameter 控制器方法
+     * @return 加密注解信息
+     */
+    private DecryptAnnotationInfoBean getMethodAnnotation(MethodParameter methodParameter) {
+        if (methodParameter.getMethod().isAnnotationPresent(DecryptBody.class)) {
+            DecryptBody decryptBody = methodParameter.getMethodAnnotation(DecryptBody.class);
+            return DecryptAnnotationInfoBean.builder()
+                    .decryptBodyMethod(decryptBody.value())
+                    .key(decryptBody.otherKey())
+                    .build();
+        }
+        if (methodParameter.getMethod().isAnnotationPresent(DESDecryptBody.class)) {
+            return DecryptAnnotationInfoBean.builder()
+                    .decryptBodyMethod(DecryptBodyMethod.DES)
+                    .key(methodParameter.getMethodAnnotation(DESDecryptBody.class).otherKey())
+                    .build();
+        }
+        if (methodParameter.getMethod().isAnnotationPresent(AESDecryptBody.class)) {
+            return DecryptAnnotationInfoBean.builder()
+                    .decryptBodyMethod(DecryptBodyMethod.AES)
+                    .key(methodParameter.getMethodAnnotation(AESDecryptBody.class).otherKey())
+                    .build();
+        }
+        return null;
+    }
+
+    /**
+     * 获取类控制器上的加密注解信息
+     *
+     * @param clazz 控制器类
+     * @return 加密注解信息
+     */
+    private DecryptAnnotationInfoBean getClassAnnotation(Class clazz) {
+        List<Annotation> annotations = new ArrayList<>(Arrays.asList(clazz.getSuperclass().getDeclaredAnnotations()));
+        annotations.addAll(Arrays.asList(clazz.getDeclaredAnnotations()));
+        for (Annotation annotation : annotations) {
+            if (annotation instanceof DecryptBody) {
+                DecryptBody decryptBody = (DecryptBody) annotation;
+                return DecryptAnnotationInfoBean.builder()
+                        .decryptBodyMethod(decryptBody.value())
+                        .key(decryptBody.otherKey())
+                        .build();
+            }
+            if (annotation instanceof DESDecryptBody) {
+                return DecryptAnnotationInfoBean.builder()
+                        .decryptBodyMethod(DecryptBodyMethod.DES)
+                        .key(((DESDecryptBody) annotation).otherKey())
+                        .build();
+            }
+            if (annotation instanceof AESDecryptBody) {
+                return DecryptAnnotationInfoBean.builder()
+                        .decryptBodyMethod(DecryptBodyMethod.AES)
+                        .key(((AESDecryptBody) annotation).otherKey())
+                        .build();
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * 选择加密方式并进行解密
+     *
+     * @param formatStringBody 目标解密字符串
+     * @param infoBean         加密信息
+     * @return 解密结果
+     */
+    private String switchDecrypt(String formatStringBody, DecryptAnnotationInfoBean infoBean) throws Exception {
+        DecryptBodyMethod method = infoBean.getDecryptBodyMethod();
+        if (method == null) throw new DecryptMethodNotFoundException();
+        String key = infoBean.getKey();
+        if (method == DecryptBodyMethod.DES) {
+            key = CheckUtils.checkAndGetKey(config.getDesKey(), key, "DES-KEY");
+            return DESEncryptUtil.decrypt(formatStringBody, key);
+        }
+        if (method == DecryptBodyMethod.AES) {
+            key = CheckUtils.checkAndGetKey(config.getAesKey(), key, "AES-KEY");
+            return AESEncryptUtil.decrypt(formatStringBody, key);
+        }
+        throw new DecryptBodyFailException();
+    }
+}

+ 234 - 0
src/main/java/cn/licoy/encryptbody/advice/EncryptResponseBodyAdvice.java

@@ -0,0 +1,234 @@
+package cn.licoy.encryptbody.advice;
+
+import cn.licoy.encryptbody.annotation.encrypt.*;
+import cn.licoy.encryptbody.bean.EncryptAnnotationInfoBean;
+import cn.licoy.encryptbody.enums.EncryptBodyMethod;
+import cn.licoy.encryptbody.enums.SHAEncryptType;
+import cn.licoy.encryptbody.exception.EncryptBodyFailException;
+import cn.licoy.encryptbody.exception.EncryptMethodNotFoundException;
+import cn.licoy.encryptbody.util.*;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import cn.licoy.encryptbody.config.EncryptBodyConfig;
+import jodd.util.ReflectUtil;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+/**
+ * 响应数据的加密处理<br>
+ * 本类只对控制器参数中含有<strong>{@link org.springframework.web.bind.annotation.ResponseBody}</strong>
+ * 或者控制类上含有<strong>{@link org.springframework.web.bind.annotation.RestController}</strong>
+ * 以及package为<strong><code>cn.licoy.encryptbody.annotation.encrypt</code></strong>下的注解有效
+ *
+ * @author licoy.cn
+ * @version 2018/9/4
+ * @see ResponseBodyAdvice
+ */
+@Order(1)
+@ControllerAdvice
+@Slf4j
+public class EncryptResponseBodyAdvice implements ResponseBodyAdvice {
+
+    private final ObjectMapper objectMapper;
+
+    private final EncryptBodyConfig config;
+
+    @Autowired
+    public EncryptResponseBodyAdvice(ObjectMapper objectMapper, EncryptBodyConfig config) {
+        this.objectMapper = objectMapper;
+        this.config = config;
+    }
+
+
+    @Override
+    public boolean supports(MethodParameter returnType, Class converterType) {
+        Annotation[] annotations = returnType.getDeclaringClass().getAnnotations();
+        if (annotations != null && annotations.length > 0) {
+            for (Annotation annotation : annotations) {
+                if (annotation instanceof EncryptBody ||
+                        annotation instanceof AESEncryptBody ||
+                        annotation instanceof DESEncryptBody ||
+                        annotation instanceof RSAEncryptBody ||
+                        annotation instanceof MD5EncryptBody ||
+                        annotation instanceof SHAEncryptBody) {
+                    return true;
+                }
+            }
+        }
+        if (Arrays.stream(ReflectUtil.getSuperclasses(returnType.getDeclaringClass()))
+                .flatMap(clazz -> Arrays.stream(clazz.getAnnotations()))
+                .anyMatch(annotation -> annotation instanceof EncryptBody ||
+                        annotation instanceof AESEncryptBody ||
+                        annotation instanceof DESEncryptBody ||
+                        annotation instanceof RSAEncryptBody ||
+                        annotation instanceof MD5EncryptBody ||
+                        annotation instanceof SHAEncryptBody)) {
+            return true;
+        }
+        return returnType.getMethod().isAnnotationPresent(EncryptBody.class) ||
+                returnType.getMethod().isAnnotationPresent(AESEncryptBody.class) ||
+                returnType.getMethod().isAnnotationPresent(DESEncryptBody.class) ||
+                returnType.getMethod().isAnnotationPresent(RSAEncryptBody.class) ||
+                returnType.getMethod().isAnnotationPresent(MD5EncryptBody.class) ||
+                returnType.getMethod().isAnnotationPresent(SHAEncryptBody.class);
+    }
+
+    @SneakyThrows
+    @Override
+    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
+                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
+        if (body == null) return null;
+        response.getHeaders().add("Content-Encrypted", "true");
+        String str = null;
+        try {
+            str = objectMapper.writeValueAsString(body);
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        }
+        EncryptAnnotationInfoBean classAnnotation = getClassAnnotation(returnType.getDeclaringClass());
+        if (classAnnotation != null) {
+            return switchEncrypt(str, classAnnotation);
+        }
+        EncryptAnnotationInfoBean methodAnnotation = getMethodAnnotation(returnType);
+        if (methodAnnotation != null) {
+            return switchEncrypt(str, methodAnnotation);
+        }
+        throw new EncryptBodyFailException();
+    }
+
+    /**
+     * 获取方法控制器上的加密注解信息
+     *
+     * @param methodParameter 控制器方法
+     * @return 加密注解信息
+     */
+    private EncryptAnnotationInfoBean getMethodAnnotation(MethodParameter methodParameter) {
+        if (methodParameter.getMethod().isAnnotationPresent(EncryptBody.class)) {
+            EncryptBody encryptBody = methodParameter.getMethodAnnotation(EncryptBody.class);
+            return EncryptAnnotationInfoBean.builder()
+                    .encryptBodyMethod(encryptBody.value())
+                    .key(encryptBody.otherKey())
+                    .shaEncryptType(encryptBody.shaType())
+                    .build();
+        }
+        if (methodParameter.getMethod().isAnnotationPresent(MD5EncryptBody.class)) {
+            return EncryptAnnotationInfoBean.builder()
+                    .encryptBodyMethod(EncryptBodyMethod.MD5)
+                    .build();
+        }
+        if (methodParameter.getMethod().isAnnotationPresent(SHAEncryptBody.class)) {
+            return EncryptAnnotationInfoBean.builder()
+                    .encryptBodyMethod(EncryptBodyMethod.SHA)
+                    .shaEncryptType(methodParameter.getMethodAnnotation(SHAEncryptBody.class).value())
+                    .build();
+        }
+        if (methodParameter.getMethod().isAnnotationPresent(DESEncryptBody.class)) {
+            return EncryptAnnotationInfoBean.builder()
+                    .encryptBodyMethod(EncryptBodyMethod.DES)
+                    .key(methodParameter.getMethodAnnotation(DESEncryptBody.class).otherKey())
+                    .build();
+        }
+        if (methodParameter.getMethod().isAnnotationPresent(AESEncryptBody.class)) {
+            return EncryptAnnotationInfoBean.builder()
+                    .encryptBodyMethod(EncryptBodyMethod.AES)
+                    .key(methodParameter.getMethodAnnotation(AESEncryptBody.class).otherKey())
+                    .build();
+        }
+        return null;
+    }
+
+    /**
+     * 获取类控制器上的加密注解信息
+     *
+     * @param clazz 控制器类
+     * @return 加密注解信息
+     */
+    private EncryptAnnotationInfoBean getClassAnnotation(Class clazz) {
+        List<Annotation> annotations = new ArrayList<>(Arrays.asList(clazz.getSuperclass().getDeclaredAnnotations()));
+        annotations.addAll(Arrays.asList(clazz.getDeclaredAnnotations()));
+        for (Annotation annotation : annotations) {
+            if (annotation instanceof EncryptBody) {
+                EncryptBody encryptBody = (EncryptBody) annotation;
+                return EncryptAnnotationInfoBean.builder()
+                        .encryptBodyMethod(encryptBody.value())
+                        .key(encryptBody.otherKey())
+                        .shaEncryptType(encryptBody.shaType())
+                        .build();
+            }
+            if (annotation instanceof MD5EncryptBody) {
+                return EncryptAnnotationInfoBean.builder()
+                        .encryptBodyMethod(EncryptBodyMethod.MD5)
+                        .build();
+            }
+            if (annotation instanceof SHAEncryptBody) {
+                return EncryptAnnotationInfoBean.builder()
+                        .encryptBodyMethod(EncryptBodyMethod.SHA)
+                        .shaEncryptType(((SHAEncryptBody) annotation).value())
+                        .build();
+            }
+            if (annotation instanceof DESEncryptBody) {
+                return EncryptAnnotationInfoBean.builder()
+                        .encryptBodyMethod(EncryptBodyMethod.DES)
+                        .key(((DESEncryptBody) annotation).otherKey())
+                        .build();
+            }
+            if (annotation instanceof AESEncryptBody) {
+                return EncryptAnnotationInfoBean.builder()
+                        .encryptBodyMethod(EncryptBodyMethod.AES)
+                        .key(((AESEncryptBody) annotation).otherKey())
+                        .build();
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * 选择加密方式并进行加密
+     *
+     * @param formatStringBody 目标加密字符串
+     * @param infoBean         加密信息
+     * @return 加密结果
+     */
+    private String switchEncrypt(String formatStringBody, EncryptAnnotationInfoBean infoBean) throws Exception {
+        EncryptBodyMethod method = infoBean.getEncryptBodyMethod();
+        if (method == null) {
+            throw new EncryptMethodNotFoundException();
+        }
+        if (method == EncryptBodyMethod.MD5) {
+            return MD5EncryptUtil.encrypt(formatStringBody);
+        }
+        if (method == EncryptBodyMethod.SHA) {
+            SHAEncryptType shaEncryptType = infoBean.getShaEncryptType();
+            if (shaEncryptType == null) shaEncryptType = SHAEncryptType.SHA256;
+            return SHAEncryptUtil.encrypt(formatStringBody, shaEncryptType);
+        }
+        String key = infoBean.getKey();
+        if (method == EncryptBodyMethod.DES) {
+            key = CheckUtils.checkAndGetKey(config.getDesKey(), key, "DES-KEY");
+            return DESEncryptUtil.encrypt(formatStringBody, key);
+        }
+        if (method == EncryptBodyMethod.AES) {
+            key = CheckUtils.checkAndGetKey(config.getAesKey(), key, "AES-KEY");
+            return AESEncryptUtil.encrypt(formatStringBody, key);
+        }
+        throw new EncryptBodyFailException();
+    }
+
+
+}

+ 230 - 0
src/main/java/cn/licoy/encryptbody/annotation/EnableEncryptBody.java

@@ -0,0 +1,230 @@
+/*
+                                   Apache License
+                             Version 2.0, January 2004
+                          http://www.apache.org/licenses/
+
+     TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+     1. Definitions.
+
+        "License" shall mean the terms and conditions for use, reproduction,
+        and distribution as defined by Sections 1 through 9 of this document.
+
+        "Licensor" shall mean the copyright owner or entity authorized by
+        the copyright owner that is granting the License.
+
+        "Legal Entity" shall mean the union of the acting entity and all
+        other entities that control, are controlled by, or are under common
+        control with that entity. For the purposes of this definition,
+        "control" means (i) the power, direct or indirect, to cause the
+        direction or management of such entity, whether by contract or
+        otherwise, or (ii) ownership of fifty percent (50%) or more of the
+        outstanding shares, or (iii) beneficial ownership of such entity.
+
+        "You" (or "Your") shall mean an individual or Legal Entity
+        exercising permissions granted by this License.
+
+        "Source" form shall mean the preferred form for making modifications,
+        including but not limited to software source code, documentation
+        source, and configuration files.
+
+        "Object" form shall mean any form resulting from mechanical
+        transformation or translation of a Source form, including but
+        not limited to compiled object code, generated documentation,
+        and conversions to other media types.
+
+        "Work" shall mean the work of authorship, whether in Source or
+        Object form, made available under the License, as indicated by a
+        copyright notice that is included in or attached to the work
+        (an example is provided in the Appendix below).
+
+        "Derivative Works" shall mean any work, whether in Source or Object
+        form, that is based on (or derived from) the Work and for which the
+        editorial revisions, annotations, elaborations, or other modifications
+        represent, as a whole, an original work of authorship. For the purposes
+        of this License, Derivative Works shall not include works that remain
+        separable from, or merely link (or bind by name) to the interfaces of,
+        the Work and Derivative Works thereof.
+
+        "Contribution" shall mean any work of authorship, including
+        the original version of the Work and any modifications or additions
+        to that Work or Derivative Works thereof, that is intentionally
+        submitted to Licensor for inclusion in the Work by the copyright owner
+        or by an individual or Legal Entity authorized to submit on behalf of
+        the copyright owner. For the purposes of this definition, "submitted"
+        means any form of electronic, verbal, or written communication sent
+        to the Licensor or its representatives, including but not limited to
+        communication on electronic mailing lists, source code control systems,
+        and issue tracking systems that are managed by, or on behalf of, the
+        Licensor for the purpose of discussing and improving the Work, but
+        excluding communication that is conspicuously marked or otherwise
+        designated in writing by the copyright owner as "Not a Contribution."
+
+        "Contributor" shall mean Licensor and any individual or Legal Entity
+        on behalf of whom a Contribution has been received by Licensor and
+        subsequently incorporated within the Work.
+
+     2. Grant of Copyright License. Subject to the terms and conditions of
+        this License, each Contributor hereby grants to You a perpetual,
+        worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+        copyright license to reproduce, prepare Derivative Works of,
+        publicly display, publicly perform, sublicense, and distribute the
+        Work and such Derivative Works in Source or Object form.
+
+     3. Grant of Patent License. Subject to the terms and conditions of
+        this License, each Contributor hereby grants to You a perpetual,
+        worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+        (except as stated in this section) patent license to make, have made,
+        use, offer to sell, sell, import, and otherwise transfer the Work,
+        where such license applies only to those patent claims licensable
+        by such Contributor that are necessarily infringed by their
+        Contribution(s) alone or by combination of their Contribution(s)
+        with the Work to which such Contribution(s) was submitted. If You
+        institute patent litigation against any entity (including a
+        cross-claim or counterclaim in a lawsuit) alleging that the Work
+        or a Contribution incorporated within the Work constitutes direct
+        or contributory patent infringement, then any patent licenses
+        granted to You under this License for that Work shall terminate
+        as of the date such litigation is filed.
+
+     4. Redistribution. You may reproduce and distribute copies of the
+        Work or Derivative Works thereof in any medium, with or without
+        modifications, and in Source or Object form, provided that You
+        meet the following conditions:
+
+        (a) You must give any other recipients of the Work or
+            Derivative Works a copy of this License; and
+
+        (b) You must cause any modified files to carry prominent notices
+            stating that You changed the files; and
+
+        (c) You must retain, in the Source form of any Derivative Works
+            that You distribute, all copyright, patent, trademark, and
+            attribution notices from the Source form of the Work,
+            excluding those notices that do not pertain to any part of
+            the Derivative Works; and
+
+        (d) If the Work includes a "NOTICE" text file as part of its
+            distribution, then any Derivative Works that You distribute must
+            include a readable copy of the attribution notices contained
+            within such NOTICE file, excluding those notices that do not
+            pertain to any part of the Derivative Works, in at least one
+            of the following places: within a NOTICE text file distributed
+            as part of the Derivative Works; within the Source form or
+            documentation, if provided along with the Derivative Works; or,
+            within a display generated by the Derivative Works, if and
+            wherever such third-party notices normally appear. The contents
+            of the NOTICE file are for informational purposes only and
+            do not modify the License. You may add Your own attribution
+            notices within Derivative Works that You distribute, alongside
+            or as an addendum to the NOTICE text from the Work, provided
+            that such additional attribution notices cannot be construed
+            as modifying the License.
+
+        You may add Your own copyright statement to Your modifications and
+        may provide additional or different license terms and conditions
+        for use, reproduction, or distribution of Your modifications, or
+        for any such Derivative Works as a whole, provided Your use,
+        reproduction, and distribution of the Work otherwise complies with
+        the conditions stated in this License.
+
+     5. Submission of Contributions. Unless You explicitly state otherwise,
+        any Contribution intentionally submitted for inclusion in the Work
+        by You to the Licensor shall be under the terms and conditions of
+        this License, without any additional terms or conditions.
+        Notwithstanding the above, nothing herein shall supersede or modify
+        the terms of any separate license agreement you may have executed
+        with Licensor regarding such Contributions.
+
+     6. Trademarks. This License does not grant permission to use the trade
+        names, trademarks, service marks, or product names of the Licensor,
+        except as required for reasonable and customary use in describing the
+        origin of the Work and reproducing the content of the NOTICE file.
+
+     7. Disclaimer of Warranty. Unless required by applicable law or
+        agreed to in writing, Licensor provides the Work (and each
+        Contributor provides its Contributions) on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+        implied, including, without limitation, any warranties or conditions
+        of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+        PARTICULAR PURPOSE. You are solely responsible for determining the
+        appropriateness of using or redistributing the Work and assume any
+        risks associated with Your exercise of permissions under this License.
+
+     8. Limitation of Liability. In no event and under no legal theory,
+        whether in tort (including negligence), contract, or otherwise,
+        unless required by applicable law (such as deliberate and grossly
+        negligent acts) or agreed to in writing, shall any Contributor be
+        liable to You for damages, including any direct, indirect, special,
+        incidental, or consequential damages of any character arising as a
+        result of this License or out of the use or inability to use the
+        Work (including but not limited to damages for loss of goodwill,
+        work stoppage, computer failure or malfunction, or any and all
+        other commercial damages or losses), even if such Contributor
+        has been advised of the possibility of such damages.
+
+     9. Accepting Warranty or Additional Liability. While redistributing
+        the Work or Derivative Works thereof, You may choose to offer,
+        and charge a fee for, acceptance of support, warranty, indemnity,
+        or other liability obligations and/or rights consistent with this
+        License. However, in accepting such obligations, You may act only
+        on Your own behalf and on Your sole responsibility, not on behalf
+        of any other Contributor, and only if You agree to indemnify,
+        defend, and hold each Contributor harmless for any liability
+        incurred by, or claims asserted against, such Contributor by reason
+        of your accepting any such warranty or additional liability.
+
+     END OF TERMS AND CONDITIONS
+
+     APPENDIX: How to apply the Apache License to your work.
+
+        To apply the Apache License to your work, attach the following
+        boilerplate notice, with the fields enclosed by brackets "[]"
+        replaced with your own identifying information. (Don't include
+        the brackets!)  The text should be enclosed in the appropriate
+        comment syntax for the file format. We also recommend that a
+        file or class name and description of purpose be included on the
+        same "printed page" as the copyright notice for easier
+        identification within third-party archives.
+
+     Copyright [yyyy] [name of copyright owner]
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ */
+package cn.licoy.encryptbody.annotation;
+
+import cn.licoy.encryptbody.advice.DecryptRequestBodyAdvice;
+import cn.licoy.encryptbody.advice.EncryptResponseBodyAdvice;
+import cn.licoy.encryptbody.config.EncryptBodyConfig;
+import cn.licoy.encryptbody.config.HttpConverterConfig;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+/**
+ * <p>启动类</p>
+ * <p>使用方法:在SpringBoot的Application启动类上添加此注解即可</p>
+ * <p>更多使用信息请参考:<a href='https://github.com/Licoy/encrypt-body-spring-boot-starter/blob/master/README.md'>README</a></p>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@Import({EncryptBodyConfig.class,
+        HttpConverterConfig.class,
+        EncryptResponseBodyAdvice.class,
+        DecryptRequestBodyAdvice.class})
+public @interface EnableEncryptBody {
+}

+ 17 - 0
src/main/java/cn/licoy/encryptbody/annotation/decrypt/AESDecryptBody.java

@@ -0,0 +1,17 @@
+package cn.licoy.encryptbody.annotation.decrypt;
+
+import java.lang.annotation.*;
+
+/**
+ * @author licoy.cn
+ * @version 2018/9/7
+ * @see DecryptBody
+ */
+@Target(value = {ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface AESDecryptBody {
+
+    String otherKey() default "";
+
+}

+ 17 - 0
src/main/java/cn/licoy/encryptbody/annotation/decrypt/DESDecryptBody.java

@@ -0,0 +1,17 @@
+package cn.licoy.encryptbody.annotation.decrypt;
+
+import java.lang.annotation.*;
+
+/**
+ * @author licoy.cn
+ * @version 2018/9/7
+ * @see DecryptBody
+ */
+@Target(value = {ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DESDecryptBody {
+
+    String otherKey() default "";
+
+}

+ 22 - 0
src/main/java/cn/licoy/encryptbody/annotation/decrypt/DecryptBody.java

@@ -0,0 +1,22 @@
+package cn.licoy.encryptbody.annotation.decrypt;
+
+import cn.licoy.encryptbody.enums.DecryptBodyMethod;
+import cn.licoy.encryptbody.enums.SHAEncryptType;
+
+import java.lang.annotation.*;
+
+/**
+ * <p>解密含有{@link org.springframework.web.bind.annotation.RequestBody}注解的参数请求数据,可用于整个控制类或者某个控制器上</p>
+ * @author licoy.cn
+ * @version 2018/9/7
+ */
+@Target(value = {ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DecryptBody {
+
+    DecryptBodyMethod value() default DecryptBodyMethod.AES;
+
+    String otherKey() default "";
+
+}

+ 14 - 0
src/main/java/cn/licoy/encryptbody/annotation/decrypt/RSADecryptBody.java

@@ -0,0 +1,14 @@
+package cn.licoy.encryptbody.annotation.decrypt;
+
+import java.lang.annotation.*;
+
+/**
+ * @author licoy.cn
+ * @version 2018/9/7
+ * @see DecryptBody
+ */
+@Target(value = {ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RSADecryptBody {
+}

+ 17 - 0
src/main/java/cn/licoy/encryptbody/annotation/encrypt/AESEncryptBody.java

@@ -0,0 +1,17 @@
+package cn.licoy.encryptbody.annotation.encrypt;
+
+import java.lang.annotation.*;
+
+/**
+ * @author licoy.cn
+ * @version 2018/9/4
+ * @see EncryptBody
+ */
+@Target(value = {ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface AESEncryptBody {
+
+    String otherKey() default "";
+
+}

+ 17 - 0
src/main/java/cn/licoy/encryptbody/annotation/encrypt/DESEncryptBody.java

@@ -0,0 +1,17 @@
+package cn.licoy.encryptbody.annotation.encrypt;
+
+import java.lang.annotation.*;
+
+/**
+ * @author licoy.cn
+ * @version 2018/9/4
+ * @see EncryptBody
+ */
+@Target(value = {ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DESEncryptBody {
+
+    String otherKey() default "";
+
+}

+ 25 - 0
src/main/java/cn/licoy/encryptbody/annotation/encrypt/EncryptBody.java

@@ -0,0 +1,25 @@
+package cn.licoy.encryptbody.annotation.encrypt;
+
+
+import cn.licoy.encryptbody.enums.EncryptBodyMethod;
+import cn.licoy.encryptbody.enums.SHAEncryptType;
+
+import java.lang.annotation.*;
+
+/**
+ * <p>加密{@link org.springframework.web.bind.annotation.ResponseBody}响应数据,可用于整个控制类或者某个控制器上</p>
+ * @author licoy.cn
+ * @version 2018/9/4
+ */
+@Target(value = {ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface EncryptBody {
+
+    EncryptBodyMethod value() default EncryptBodyMethod.MD5;
+
+    String otherKey() default "";
+
+    SHAEncryptType shaType() default SHAEncryptType.SHA256;
+
+}

+ 14 - 0
src/main/java/cn/licoy/encryptbody/annotation/encrypt/MD5EncryptBody.java

@@ -0,0 +1,14 @@
+package cn.licoy.encryptbody.annotation.encrypt;
+
+import java.lang.annotation.*;
+
+/**
+ * @author licoy.cn
+ * @version 2018/9/4
+ * @see EncryptBody
+ */
+@Target(value = {ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface MD5EncryptBody {
+}

+ 14 - 0
src/main/java/cn/licoy/encryptbody/annotation/encrypt/RSAEncryptBody.java

@@ -0,0 +1,14 @@
+package cn.licoy.encryptbody.annotation.encrypt;
+
+import java.lang.annotation.*;
+
+/**
+ * @author licoy.cn
+ * @version 2018/9/4
+ * @see EncryptBody
+ */
+@Target(value = {ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RSAEncryptBody {
+}

+ 19 - 0
src/main/java/cn/licoy/encryptbody/annotation/encrypt/SHAEncryptBody.java

@@ -0,0 +1,19 @@
+package cn.licoy.encryptbody.annotation.encrypt;
+
+import cn.licoy.encryptbody.enums.SHAEncryptType;
+
+import java.lang.annotation.*;
+
+/**
+ * @author licoy.cn
+ * @version 2018/9/4
+ * @see EncryptBody
+ */
+@Target(value = {ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface SHAEncryptBody {
+
+    SHAEncryptType value() default SHAEncryptType.SHA256;
+
+}

+ 26 - 0
src/main/java/cn/licoy/encryptbody/bean/DecryptAnnotationInfoBean.java

@@ -0,0 +1,26 @@
+package cn.licoy.encryptbody.bean;
+
+import cn.licoy.encryptbody.enums.DecryptBodyMethod;
+import cn.licoy.encryptbody.enums.EncryptBodyMethod;
+import cn.licoy.encryptbody.enums.SHAEncryptType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * <p>解密注解信息</p>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class DecryptAnnotationInfoBean {
+
+    private DecryptBodyMethod decryptBodyMethod;
+
+    private String key;
+
+}

+ 33 - 0
src/main/java/cn/licoy/encryptbody/bean/DecryptHttpInputMessage.java

@@ -0,0 +1,33 @@
+package cn.licoy.encryptbody.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpInputMessage;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <p>解密信息输入流</p>
+ * @author licoy.cn
+ * @version 2018/9/7
+ */
+@NoArgsConstructor
+@AllArgsConstructor
+public class DecryptHttpInputMessage implements HttpInputMessage {
+
+    private InputStream body;
+
+    private HttpHeaders headers;
+
+    @Override
+    public InputStream getBody() throws IOException {
+        return body;
+    }
+
+    @Override
+    public HttpHeaders getHeaders() {
+        return headers;
+    }
+}

+ 27 - 0
src/main/java/cn/licoy/encryptbody/bean/EncryptAnnotationInfoBean.java

@@ -0,0 +1,27 @@
+package cn.licoy.encryptbody.bean;
+
+import cn.licoy.encryptbody.enums.EncryptBodyMethod;
+import cn.licoy.encryptbody.enums.SHAEncryptType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * <p>加密注解信息</p>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class EncryptAnnotationInfoBean {
+
+    private EncryptBodyMethod encryptBodyMethod;
+
+    private String key;
+
+    private SHAEncryptType shaEncryptType;
+
+}

+ 32 - 0
src/main/java/cn/licoy/encryptbody/config/EncryptBodyConfig.java

@@ -0,0 +1,32 @@
+package cn.licoy.encryptbody.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * <p>加密数据配置读取类</p>
+ * <p>在SpringBoot项目中的application.yml中添加配置信息即可</p>
+ * <pre>
+ *     encrypt:
+ *      body:
+ *       aes-key: 12345678 # AES加密秘钥
+ *       des-key: 12345678 # DES加密秘钥
+ * </pre>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+@ConfigurationProperties(prefix = "encrypt.body")
+@Configuration
+@Data
+public class EncryptBodyConfig {
+
+    private String aesKey;
+
+    private String desKey;
+
+    private String encoding = "UTF-8";
+
+
+
+}

+ 51 - 0
src/main/java/cn/licoy/encryptbody/config/HttpConverterConfig.java

@@ -0,0 +1,51 @@
+package cn.licoy.encryptbody.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpOutputMessage;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.util.StreamUtils;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * <p>响应体数据处理,防止数据类型为String时再进行JSON数据转换,那么产生最终的结果可能被双引号包含...</p>
+ * @author licoy.cn
+ * @version 2018/9/5
+ */
+@Configuration
+public class HttpConverterConfig extends WebMvcConfigurerAdapter {
+
+    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
+        return new MappingJackson2HttpMessageConverter(){
+            @Override
+            protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
+                if(object instanceof String){
+                    Charset charset = this.getDefaultCharset();
+                    StreamUtils.copy((String)object, charset, outputMessage.getBody());
+                }else{
+                    super.writeInternal(object, type, outputMessage);
+                }
+            }
+        };
+    }
+
+    @Override
+    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
+        MappingJackson2HttpMessageConverter converter = mappingJackson2HttpMessageConverter();
+        converter.setSupportedMediaTypes(new LinkedList<MediaType>(){{
+            add(MediaType.TEXT_HTML);
+            add(MediaType.APPLICATION_JSON_UTF8);
+        }});
+        converters.add(new StringHttpMessageConverter());
+        converters.add(converter);
+    }
+}

+ 12 - 0
src/main/java/cn/licoy/encryptbody/enums/DecryptBodyMethod.java

@@ -0,0 +1,12 @@
+package cn.licoy.encryptbody.enums;
+
+/**
+ * <p>解密方式</p>
+ * @author licoy.cn
+ * @version 2018/9/4
+ */
+public enum DecryptBodyMethod {
+
+    DES,AES,RSA
+
+}

+ 12 - 0
src/main/java/cn/licoy/encryptbody/enums/EncryptBodyMethod.java

@@ -0,0 +1,12 @@
+package cn.licoy.encryptbody.enums;
+
+/**
+ * <p>加密方式</p>
+ * @author licoy.cn
+ * @version 2018/9/4
+ */
+public enum EncryptBodyMethod {
+
+    MD5,DES,AES,SHA,RSA
+
+}

+ 22 - 0
src/main/java/cn/licoy/encryptbody/enums/SHAEncryptType.java

@@ -0,0 +1,22 @@
+package cn.licoy.encryptbody.enums;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * <p>SHA加密类型</p>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+@AllArgsConstructor
+public enum  SHAEncryptType {
+
+    SHA224("sha-224"),
+    SHA256("sha-256"),
+    SHA384("sha-384"),
+    SHA512("sha-512"),
+    ;
+
+    public String value;
+
+
+}

+ 17 - 0
src/main/java/cn/licoy/encryptbody/exception/DecryptBodyFailException.java

@@ -0,0 +1,17 @@
+package cn.licoy.encryptbody.exception;
+
+/**
+ * <p>解密数据失败异常</p>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+public class DecryptBodyFailException extends RuntimeException {
+
+    public DecryptBodyFailException() {
+        super("Decrypting data failed. (解密数据失败)");
+    }
+
+    public DecryptBodyFailException(String message) {
+        super(message);
+    }
+}

+ 17 - 0
src/main/java/cn/licoy/encryptbody/exception/DecryptMethodNotFoundException.java

@@ -0,0 +1,17 @@
+package cn.licoy.encryptbody.exception;
+
+/**
+ * <p>加密方式未找到或未定义异常</p>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+public class DecryptMethodNotFoundException extends RuntimeException {
+
+    public DecryptMethodNotFoundException() {
+        super("Decryption method is not defined. (解密方式未定义)");
+    }
+
+    public DecryptMethodNotFoundException(String message) {
+        super(message);
+    }
+}

+ 17 - 0
src/main/java/cn/licoy/encryptbody/exception/EncryptBodyFailException.java

@@ -0,0 +1,17 @@
+package cn.licoy.encryptbody.exception;
+
+/**
+ * <p>加密数据失败异常</p>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+public class EncryptBodyFailException  extends RuntimeException {
+
+    public EncryptBodyFailException() {
+        super("Encrypted data failed. (加密数据失败)");
+    }
+
+    public EncryptBodyFailException(String message) {
+        super(message);
+    }
+}

+ 17 - 0
src/main/java/cn/licoy/encryptbody/exception/EncryptMethodNotFoundException.java

@@ -0,0 +1,17 @@
+package cn.licoy.encryptbody.exception;
+
+/**
+ * <p>加密方式未找到或未定义异常</p>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+public class EncryptMethodNotFoundException extends RuntimeException {
+
+    public EncryptMethodNotFoundException() {
+        super("Encryption method is not defined. (加密方式未定义)");
+    }
+
+    public EncryptMethodNotFoundException(String message) {
+        super(message);
+    }
+}

+ 17 - 0
src/main/java/cn/licoy/encryptbody/exception/KeyNotConfiguredException.java

@@ -0,0 +1,17 @@
+package cn.licoy.encryptbody.exception;
+
+
+import lombok.NoArgsConstructor;
+
+/**
+ * <p>未配置KEY运行时异常</p>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+@NoArgsConstructor
+public class KeyNotConfiguredException extends RuntimeException {
+
+    public KeyNotConfiguredException(String message) {
+        super(message);
+    }
+}

+ 64 - 0
src/main/java/cn/licoy/encryptbody/util/AESEncryptUtil.java

@@ -0,0 +1,64 @@
+package cn.licoy.encryptbody.util;
+
+import javax.crypto.*;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+/**
+ * <p>AES加密处理工具类</p>
+ *
+ * @author licoy.cn
+ * @version 2018/9/5
+ */
+public class AESEncryptUtil {
+
+    /**
+     * AES加密
+     *
+     * @param content  字符串内容
+     * @param password 密钥
+     */
+    public static String encrypt(String content, String password) throws Exception {
+        return aes(content, password, Cipher.ENCRYPT_MODE);
+    }
+
+
+    /**
+     * AES解密
+     *
+     * @param content  字符串内容
+     * @param password 密钥
+     */
+    public static String decrypt(String content, String password) throws Exception {
+        return aes(content, password, Cipher.DECRYPT_MODE);
+    }
+
+    /**
+     * AES加密/解密 公共方法
+     *
+     * @param content  字符串
+     * @param password 密钥
+     * @param type     加密:{@link Cipher#ENCRYPT_MODE},解密:{@link Cipher#DECRYPT_MODE}
+     */
+    private static String aes(String content, String password, int type) throws Exception {
+        KeyGenerator generator = KeyGenerator.getInstance("AES");
+        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+        random.setSeed(password.getBytes());
+        generator.init(128, random);
+        SecretKey secretKey = generator.generateKey();
+        byte[] enCodeFormat = secretKey.getEncoded();
+        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
+        Cipher cipher = Cipher.getInstance("AES");
+        cipher.init(type, key);
+        if (type == Cipher.ENCRYPT_MODE) {
+            byte[] byteContent = content.getBytes("utf-8");
+            return Hex2Util.parseByte2HexStr(cipher.doFinal(byteContent));
+        } else {
+            byte[] byteContent = Hex2Util.parseHexStr2Byte(content);
+            return new String(cipher.doFinal(byteContent));
+        }
+    }
+}

+ 20 - 0
src/main/java/cn/licoy/encryptbody/util/CheckUtils.java

@@ -0,0 +1,20 @@
+package cn.licoy.encryptbody.util;
+
+import cn.licoy.encryptbody.exception.KeyNotConfiguredException;
+
+/**
+ * <p>辅助检测工具类</p>
+ * @author licoy.cn
+ * @version 2018/9/7
+ */
+public class CheckUtils {
+
+    public static String checkAndGetKey(String k1,String k2,String keyName){
+        if(StringUtils.isNullOrEmpty(k1) && StringUtils.isNullOrEmpty(k2)){
+            throw new KeyNotConfiguredException(String.format("%s is not configured (未配置%s)", keyName,keyName));
+        }
+        if(k1==null) return k2;
+        return k1;
+    }
+
+}

+ 65 - 0
src/main/java/cn/licoy/encryptbody/util/DESEncryptUtil.java

@@ -0,0 +1,65 @@
+package cn.licoy.encryptbody.util;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.DESKeySpec;
+import java.security.SecureRandom;
+
+/**
+ * <p>DES加密处理工具类</p>
+ * @author licoy.cn
+ * @version 2018/9/5
+ */
+public class DESEncryptUtil {
+
+    /**
+     * DES加密
+     * @param content  字符串内容
+     * @param password 密钥
+     */
+    public static String encrypt(String content, String password){
+        return des(content,password,Cipher.ENCRYPT_MODE);
+    }
+
+
+    /**
+     * DES解密
+     * @param content  字符串内容
+     * @param password 密钥
+     */
+    public static String decrypt(String content, String password){
+        return des(content,password,Cipher.DECRYPT_MODE);
+    }
+
+
+    /**
+     * DES加密/解密公共方法
+     * @param content  字符串内容
+     * @param password 密钥
+     * @param type     加密:{@link Cipher#ENCRYPT_MODE},解密:{@link Cipher#DECRYPT_MODE}
+     */
+    private static String des(String content, String password, int type) {
+        try {
+            SecureRandom random = new SecureRandom();
+            DESKeySpec desKey = new DESKeySpec(password.getBytes());
+            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
+            Cipher cipher = Cipher.getInstance("DES");
+            cipher.init(type, keyFactory.generateSecret(desKey), random);
+
+            if (type == Cipher.ENCRYPT_MODE) {
+                byte[] byteContent = content.getBytes("utf-8");
+                return Hex2Util.parseByte2HexStr(cipher.doFinal(byteContent));
+            } else {
+                byte[] byteContent = Hex2Util.parseHexStr2Byte(content);
+                assert byteContent != null;
+                return new String(cipher.doFinal(byteContent));
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+
+}

+ 44 - 0
src/main/java/cn/licoy/encryptbody/util/Hex2Util.java

@@ -0,0 +1,44 @@
+package cn.licoy.encryptbody.util;
+
+/**
+ * <p>二进制转换工具类</p>
+ * @author licoy.cn
+ * @version 2018/9/5
+ */
+public class Hex2Util {
+
+    /**
+     * 二进位组转十六进制字符串
+     * @param buf 二进位组
+     * @return 十六进制字符串
+     */
+    public static String parseByte2HexStr(byte buf[]) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : buf) {
+            String hex = Integer.toHexString(b & 0xFF);
+            if (hex.length() == 1) {
+                hex = '0' + hex;
+            }
+            sb.append(hex.toUpperCase());
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 十六进制字符串转二进位组
+     * @param hexStr 十六进制字符串
+     * @return 二进位组
+     */
+    public static byte[] parseHexStr2Byte(String hexStr) {
+        if (hexStr.length() < 1) return null;
+        byte[] result = new byte[hexStr.length() / 2];
+
+        for (int i = 0; i < hexStr.length() / 2; i++) {
+            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
+            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
+            result[i] = (byte) (high * 16 + low);
+        }
+        return result;
+    }
+
+}

+ 34 - 0
src/main/java/cn/licoy/encryptbody/util/MD5EncryptUtil.java

@@ -0,0 +1,34 @@
+package cn.licoy.encryptbody.util;
+
+import java.security.MessageDigest;
+
+/**
+ * <p>MD5加密工具类</p>
+ * @author licoy.cn
+ * @version 2017/11/18
+ */
+public class MD5EncryptUtil {
+
+    /**
+     * MD5加密-32位小写
+     * */
+    public static String encrypt(String encryptStr) {
+        MessageDigest md5;
+        try {
+            md5 = MessageDigest.getInstance("MD5");
+            byte[] md5Bytes = md5.digest(encryptStr.getBytes());
+            StringBuilder hexValue = new StringBuilder();
+            for (byte md5Byte : md5Bytes) {
+                int val = ((int) md5Byte) & 0xff;
+                if (val < 16)
+                    hexValue.append("0");
+                hexValue.append(Integer.toHexString(val));
+            }
+            encryptStr = hexValue.toString();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return encryptStr;
+    }
+
+}

+ 44 - 0
src/main/java/cn/licoy/encryptbody/util/SHAEncryptUtil.java

@@ -0,0 +1,44 @@
+
+
+package cn.licoy.encryptbody.util;
+
+
+import cn.licoy.encryptbody.enums.SHAEncryptType;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * <p>SHA加密工具类</p>
+ * @author licoy.cn
+ * @version 2018/9/5
+ */
+public class SHAEncryptUtil {
+
+
+    /**
+     * SHA加密公共方法
+     * @param string 目标字符串
+     * @param type   加密类型 {@link SHAEncryptType}
+     */
+    public static String encrypt(String string,SHAEncryptType type) {
+        if (string==null || "".equals(string.trim())) return "";
+        if (type==null) type = SHAEncryptType.SHA256;
+        try {
+            MessageDigest md5 = MessageDigest.getInstance(type.value);
+            byte[] bytes = md5.digest((string).getBytes());
+            StringBuilder result = new StringBuilder();
+            for (byte b : bytes) {
+                String temp = Integer.toHexString(b & 0xff);
+                if (temp.length() == 1) {
+                    temp = "0" + temp;
+                }
+                result.append(temp);
+            }
+            return result.toString();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+}

+ 14 - 0
src/main/java/cn/licoy/encryptbody/util/StringUtils.java

@@ -0,0 +1,14 @@
+package cn.licoy.encryptbody.util;
+
+/**
+ * <p>字符串处理工具类</p>
+ * @author licoy.cn
+ * @version 2018/9/6
+ */
+public class StringUtils {
+
+    public static boolean isNullOrEmpty(String string) {
+        return string == null || string.length() == 0;
+    }
+
+}

+ 2 - 0
src/main/java/com/izouma/nineth/Application.java

@@ -1,5 +1,6 @@
 package com.izouma.nineth;
 
+import cn.licoy.encryptbody.annotation.EnableEncryptBody;
 import com.fasterxml.jackson.core.Version;
 import com.fasterxml.jackson.databind.module.SimpleModule;
 import com.fasterxml.jackson.databind.Module;
@@ -21,6 +22,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
 @EnableScheduling
 @EnableAsync
 @EnableRetry
+@EnableEncryptBody
 public class Application {
 
     public static void main(String[] args) {

+ 1 - 1
src/main/java/com/izouma/nineth/config/WebMvcConfig.java

@@ -107,7 +107,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
                 .allowedOriginPatterns("*")
                 .allowCredentials(true)
                 .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH")
-                .exposedHeaders("Content-Disposition");
+                .exposedHeaders("Content-Disposition,Content-Encrypted");
     }
 
 }

+ 3 - 0
src/main/java/com/izouma/nineth/web/AssetController.java

@@ -1,5 +1,7 @@
 package com.izouma.nineth.web;
 
+import cn.licoy.encryptbody.annotation.encrypt.EncryptBody;
+import cn.licoy.encryptbody.enums.EncryptBodyMethod;
 import com.fasterxml.jackson.annotation.JsonView;
 import com.izouma.nineth.TokenHistory;
 import com.izouma.nineth.domain.Asset;
@@ -171,6 +173,7 @@ public class AssetController extends BaseController {
 
     @GetMapping("/tokenHistory")
     @ApiOperation("交易历史")
+    @EncryptBody(EncryptBodyMethod.AES)
     public List<TokenHistory> tokenHistory(@RequestParam(required = false) String tokenId, @RequestParam(required = false) Long assetId) {
         return assetService.tokenHistory(tokenId, assetId);
     }

+ 4 - 0
src/main/resources/application.yaml

@@ -248,6 +248,10 @@ hmpay:
 payease:
   merchant-id: 896593123
   notify-url: http://raex.frp.izouma.com/payease/notify
+encrypt:
+  body:
+    aes-key: 2wAtaTUoJMjSsJRsAzKFZ83ArFf4tV8P
+  enable: false
 ---
 
 spring: