EncryptResponseBodyAdvice.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. package cn.licoy.encryptbody.advice;
  2. import cn.licoy.encryptbody.annotation.encrypt.*;
  3. import cn.licoy.encryptbody.bean.EncryptAnnotationInfoBean;
  4. import cn.licoy.encryptbody.enums.EncryptBodyMethod;
  5. import cn.licoy.encryptbody.enums.SHAEncryptType;
  6. import cn.licoy.encryptbody.exception.EncryptBodyFailException;
  7. import cn.licoy.encryptbody.exception.EncryptMethodNotFoundException;
  8. import cn.licoy.encryptbody.util.*;
  9. import com.fasterxml.jackson.core.JsonProcessingException;
  10. import com.fasterxml.jackson.databind.ObjectMapper;
  11. import cn.licoy.encryptbody.config.EncryptBodyConfig;
  12. import jodd.util.ReflectUtil;
  13. import lombok.SneakyThrows;
  14. import lombok.extern.slf4j.Slf4j;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.core.MethodParameter;
  17. import org.springframework.core.annotation.Order;
  18. import org.springframework.http.MediaType;
  19. import org.springframework.http.server.ServerHttpRequest;
  20. import org.springframework.http.server.ServerHttpResponse;
  21. import org.springframework.web.bind.annotation.ControllerAdvice;
  22. import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
  23. import java.lang.annotation.Annotation;
  24. import java.util.ArrayList;
  25. import java.util.Arrays;
  26. import java.util.List;
  27. import java.util.stream.Collectors;
  28. /**
  29. * 响应数据的加密处理<br>
  30. * 本类只对控制器参数中含有<strong>{@link org.springframework.web.bind.annotation.ResponseBody}</strong>
  31. * 或者控制类上含有<strong>{@link org.springframework.web.bind.annotation.RestController}</strong>
  32. * 以及package为<strong><code>cn.licoy.encryptbody.annotation.encrypt</code></strong>下的注解有效
  33. *
  34. * @author licoy.cn
  35. * @version 2018/9/4
  36. * @see ResponseBodyAdvice
  37. */
  38. @Order(1)
  39. @ControllerAdvice
  40. @Slf4j
  41. public class EncryptResponseBodyAdvice implements ResponseBodyAdvice {
  42. private final ObjectMapper objectMapper;
  43. private final EncryptBodyConfig config;
  44. @Autowired
  45. public EncryptResponseBodyAdvice(ObjectMapper objectMapper, EncryptBodyConfig config) {
  46. this.objectMapper = objectMapper;
  47. this.config = config;
  48. }
  49. @Override
  50. public boolean supports(MethodParameter returnType, Class converterType) {
  51. Annotation[] annotations = returnType.getDeclaringClass().getAnnotations();
  52. if (annotations != null && annotations.length > 0) {
  53. for (Annotation annotation : annotations) {
  54. if (annotation instanceof EncryptBody ||
  55. annotation instanceof AESEncryptBody ||
  56. annotation instanceof DESEncryptBody ||
  57. annotation instanceof RSAEncryptBody ||
  58. annotation instanceof MD5EncryptBody ||
  59. annotation instanceof SHAEncryptBody) {
  60. return true;
  61. }
  62. }
  63. }
  64. if (Arrays.stream(ReflectUtil.getSuperclasses(returnType.getDeclaringClass()))
  65. .flatMap(clazz -> Arrays.stream(clazz.getAnnotations()))
  66. .anyMatch(annotation -> annotation instanceof EncryptBody ||
  67. annotation instanceof AESEncryptBody ||
  68. annotation instanceof DESEncryptBody ||
  69. annotation instanceof RSAEncryptBody ||
  70. annotation instanceof MD5EncryptBody ||
  71. annotation instanceof SHAEncryptBody)) {
  72. return true;
  73. }
  74. return returnType.getMethod().isAnnotationPresent(EncryptBody.class) ||
  75. returnType.getMethod().isAnnotationPresent(AESEncryptBody.class) ||
  76. returnType.getMethod().isAnnotationPresent(DESEncryptBody.class) ||
  77. returnType.getMethod().isAnnotationPresent(RSAEncryptBody.class) ||
  78. returnType.getMethod().isAnnotationPresent(MD5EncryptBody.class) ||
  79. returnType.getMethod().isAnnotationPresent(SHAEncryptBody.class);
  80. }
  81. @SneakyThrows
  82. @Override
  83. public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
  84. Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
  85. if (body == null) return null;
  86. response.getHeaders().add("Content-Encrypted", "true");
  87. String str = null;
  88. try {
  89. str = objectMapper.writeValueAsString(body);
  90. } catch (JsonProcessingException e) {
  91. e.printStackTrace();
  92. }
  93. EncryptAnnotationInfoBean classAnnotation = getClassAnnotation(returnType.getDeclaringClass());
  94. if (classAnnotation != null) {
  95. return switchEncrypt(str, classAnnotation);
  96. }
  97. EncryptAnnotationInfoBean methodAnnotation = getMethodAnnotation(returnType);
  98. if (methodAnnotation != null) {
  99. return switchEncrypt(str, methodAnnotation);
  100. }
  101. throw new EncryptBodyFailException();
  102. }
  103. /**
  104. * 获取方法控制器上的加密注解信息
  105. *
  106. * @param methodParameter 控制器方法
  107. * @return 加密注解信息
  108. */
  109. private EncryptAnnotationInfoBean getMethodAnnotation(MethodParameter methodParameter) {
  110. if (methodParameter.getMethod().isAnnotationPresent(EncryptBody.class)) {
  111. EncryptBody encryptBody = methodParameter.getMethodAnnotation(EncryptBody.class);
  112. return EncryptAnnotationInfoBean.builder()
  113. .encryptBodyMethod(encryptBody.value())
  114. .key(encryptBody.otherKey())
  115. .shaEncryptType(encryptBody.shaType())
  116. .build();
  117. }
  118. if (methodParameter.getMethod().isAnnotationPresent(MD5EncryptBody.class)) {
  119. return EncryptAnnotationInfoBean.builder()
  120. .encryptBodyMethod(EncryptBodyMethod.MD5)
  121. .build();
  122. }
  123. if (methodParameter.getMethod().isAnnotationPresent(SHAEncryptBody.class)) {
  124. return EncryptAnnotationInfoBean.builder()
  125. .encryptBodyMethod(EncryptBodyMethod.SHA)
  126. .shaEncryptType(methodParameter.getMethodAnnotation(SHAEncryptBody.class).value())
  127. .build();
  128. }
  129. if (methodParameter.getMethod().isAnnotationPresent(DESEncryptBody.class)) {
  130. return EncryptAnnotationInfoBean.builder()
  131. .encryptBodyMethod(EncryptBodyMethod.DES)
  132. .key(methodParameter.getMethodAnnotation(DESEncryptBody.class).otherKey())
  133. .build();
  134. }
  135. if (methodParameter.getMethod().isAnnotationPresent(AESEncryptBody.class)) {
  136. return EncryptAnnotationInfoBean.builder()
  137. .encryptBodyMethod(EncryptBodyMethod.AES)
  138. .key(methodParameter.getMethodAnnotation(AESEncryptBody.class).otherKey())
  139. .build();
  140. }
  141. return null;
  142. }
  143. /**
  144. * 获取类控制器上的加密注解信息
  145. *
  146. * @param clazz 控制器类
  147. * @return 加密注解信息
  148. */
  149. private EncryptAnnotationInfoBean getClassAnnotation(Class clazz) {
  150. List<Annotation> annotations = new ArrayList<>(Arrays.asList(clazz.getSuperclass().getDeclaredAnnotations()));
  151. annotations.addAll(Arrays.asList(clazz.getDeclaredAnnotations()));
  152. for (Annotation annotation : annotations) {
  153. if (annotation instanceof EncryptBody) {
  154. EncryptBody encryptBody = (EncryptBody) annotation;
  155. return EncryptAnnotationInfoBean.builder()
  156. .encryptBodyMethod(encryptBody.value())
  157. .key(encryptBody.otherKey())
  158. .shaEncryptType(encryptBody.shaType())
  159. .build();
  160. }
  161. if (annotation instanceof MD5EncryptBody) {
  162. return EncryptAnnotationInfoBean.builder()
  163. .encryptBodyMethod(EncryptBodyMethod.MD5)
  164. .build();
  165. }
  166. if (annotation instanceof SHAEncryptBody) {
  167. return EncryptAnnotationInfoBean.builder()
  168. .encryptBodyMethod(EncryptBodyMethod.SHA)
  169. .shaEncryptType(((SHAEncryptBody) annotation).value())
  170. .build();
  171. }
  172. if (annotation instanceof DESEncryptBody) {
  173. return EncryptAnnotationInfoBean.builder()
  174. .encryptBodyMethod(EncryptBodyMethod.DES)
  175. .key(((DESEncryptBody) annotation).otherKey())
  176. .build();
  177. }
  178. if (annotation instanceof AESEncryptBody) {
  179. return EncryptAnnotationInfoBean.builder()
  180. .encryptBodyMethod(EncryptBodyMethod.AES)
  181. .key(((AESEncryptBody) annotation).otherKey())
  182. .build();
  183. }
  184. }
  185. return null;
  186. }
  187. /**
  188. * 选择加密方式并进行加密
  189. *
  190. * @param formatStringBody 目标加密字符串
  191. * @param infoBean 加密信息
  192. * @return 加密结果
  193. */
  194. private String switchEncrypt(String formatStringBody, EncryptAnnotationInfoBean infoBean) throws Exception {
  195. EncryptBodyMethod method = infoBean.getEncryptBodyMethod();
  196. if (method == null) {
  197. throw new EncryptMethodNotFoundException();
  198. }
  199. if (method == EncryptBodyMethod.MD5) {
  200. return MD5EncryptUtil.encrypt(formatStringBody);
  201. }
  202. if (method == EncryptBodyMethod.SHA) {
  203. SHAEncryptType shaEncryptType = infoBean.getShaEncryptType();
  204. if (shaEncryptType == null) shaEncryptType = SHAEncryptType.SHA256;
  205. return SHAEncryptUtil.encrypt(formatStringBody, shaEncryptType);
  206. }
  207. String key = infoBean.getKey();
  208. if (method == EncryptBodyMethod.DES) {
  209. key = CheckUtils.checkAndGetKey(config.getDesKey(), key, "DES-KEY");
  210. return DESEncryptUtil.encrypt(formatStringBody, key);
  211. }
  212. if (method == EncryptBodyMethod.AES) {
  213. key = CheckUtils.checkAndGetKey(config.getAesKey(), key, "AES-KEY");
  214. return AESEncryptUtil.encrypt(formatStringBody, key);
  215. }
  216. throw new EncryptBodyFailException();
  217. }
  218. }