在开发中,有时候会遇到前端body加密,后端解密操作,接下来用注解实现
1、新增DecodeRequestBodyAdvice类
package com.xx.advice;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
@ControllerAdvice(basePackages = "com.xx.controller")
@Slf4j
public class DecodeRequestBodyAdvice implements RequestBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return body;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
try {
boolean encode = false;
if (methodParameter.getMethod().isAnnotationPresent(AesDecrypt.class)) {
//获取注解配置的包含和去除字段
AesDecrypt serializedField = methodParameter.getMethodAnnotation(AesDecrypt.class);
//入参是否需要解密
encode = serializedField.inDecode();
}
if (encode) {
log.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密");
return new MyHttpInputMessage(inputMessage);
} else {
return inputMessage;
}
} catch (Exception e) {
e.printStackTrace();
log.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:" + e.getMessage());
return inputMessage;
}
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return body;
}
class MyHttpInputMessage implements HttpInputMessage {
private HttpHeaders headers;
private InputStream body;
public MyHttpInputMessage(HttpInputMessage httpInputMessage) throws Exception {
this.headers = httpInputMessage.getHeaders();
String requestData = IOUtils.toString(httpInputMessage.getBody(), "utf-8");
System.out.println("--encryptStr:" + requestData);
String encryptStr = easpString(requestData).replace("\"", "");
String decrypt = AESUtil.decrypt(encryptStr);
this.body = IOUtils.toInputStream(decrypt, "utf-8");
}
@Override
public InputStream getBody() throws IOException {
return body;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
public String easpString(String requestData) {
if (requestData != null && !requestData.equals("")) {
String s = "{\"encryptStr\":";
//去除requestData中的转义字符
String data = requestData.replaceAll("\\s*|\r|\n|\t", "");
if (!data.startsWith(s)) {
throw new RuntimeException("参数【encryptStr】缺失异常!");
} else {
int closeLen = data.length() - 1;
int openLen = "{\"encryptStr\":".length();
String substring = StringUtils.substring(data, openLen, closeLen);
return substring;
}
}
return "";
}
}
}
2、新增AesDecrypt
package com.xx.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface AesDecrypt {
//入参是否解密,默认解密
boolean inDecode() default true;
//出参是否加密,默认加密
boolean outEncode() default true;
}
注意:AESUtil可以直接网上copy一份,和前端一一对应加密秘钥
3、使用
@PostMapping("/addUser")
@AesDecrypt
public ResponseBean<String> addUser(@RequestBody UserLoginRequest loginRequest) {
ResponseBean<String> responseBean = new ResponseBean<>();
sysUserService.addUser(loginRequest);
responseBean.setSuccess(true);
responseBean.setMessage("新增用户成功");
return responseBean;
}
即可解密
4、前端请求body
{"encryptStr":"加密body"}