注解主要用来指定那些需要加解密的controller方法,实现比较简单
1 2 3 4 5 6 | @Target ({ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) public @interface SecretAnnotation { boolean encode() default false ; boolean decode() default false ; } |
使用时添加注解在controller的方法上
1 2 3 4 5 | @PostMapping ( "/preview" ) @SecretAnnotation (decode = true ) public ResponseVO<ContractSignVO> previewContract( @RequestBody FillContractDTO fillContractDTO) { return contractSignService.previewContract(fillContractDTO); } |
请求数据由二进制流转为类对象数据,对于加密过的数据,需要在二进制流被处理之前进行解密,否则在转为类对象时会因为数据格式不匹配而报错。
因此使用RequestBodyAdvice的beforeBodyRead方法来处理。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | @Slf4j @RestControllerAdvice public class MyRequestControllerAdvice implements RequestBodyAdvice { @Override public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) { return methodParameter.hasParameterAnnotation(RequestBody. class ); } @Override public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) { return o; } @Autowired private MySecretUtil mySecretUtil; @Override public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException { if (methodParameter.getMethod().isAnnotationPresent(SecretAnnotation. class )) { SecretAnnotation secretAnnotation = methodParameter.getMethod().getAnnotation(SecretAnnotation. class ); if (secretAnnotation.decode()) { return new HttpInputMessage() { @Override public InputStream getBody() throws IOException { List<String> appIdList = httpInputMessage.getHeaders().get( "appId" ); if (appIdList.isEmpty()){ throw new RuntimeException( "请求头缺少appID" ); } String appId = appIdList.get( 0 ); String bodyStr = IOUtils.toString(httpInputMessage.getBody(), "utf-8" ); bodyStr = mySecretUtil.decode(bodyStr,appId); return IOUtils.toInputStream(bodyStr, "utf-8" ); } @Override public HttpHeaders getHeaders() { return httpInputMessage.getHeaders(); } }; } } return httpInputMessage; } @Override public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) { return o; } } |
mySecretUtil.decode(bodyStr,appId)的内容是,通过请求头中的AppID去数据库中查找对于的秘钥,之后进行解密,返回解密后的字符串。再通过common.io包中提供的工具类IOUtils将字符串转为inputstream流,替换HttpInputMessage,返回一个body数据为解密后的二进制流的HttpInputMessage。
1 2 3 4 5 | < dependency > < groupId >commons-io</ groupId > < artifactId >commons-io</ artifactId > < version >2.6</ version > </ dependency > |