由于有些项目需要对于安全要求比较高的情况下,可以使用这种方式对请求参数和返回参数进行加密解密的操作。
RequestBodyAdvice
主要作用是拦截请求的数据,对数据进行处理(RequestBodyAdvice仅对使用了@RqestBody注解的生效,因为它原理上还是AOP ,所以GET方法是不会操作的)
ResponseBodyAdvice
主要作用是拦截返回的数据,对数据进行处理
@RestControllerAdvice
或@ControllerAdvice
使用代码
maven依赖(自行查看项目中是否已经存在相关依赖了)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.15</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.1</version>
</dependency>
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.45</version>
</dependency>
自定义requestBody拦截器
/**
* 拦截请求(可以对参数解密等操作)
* RequestBodyAdvice仅对使用了@RqestBody注解的生效,因为它原理上还是AOP ,所以GET方法是不会操作的
*/
@ControllerAdvice
@Slf4j
public class RequestBody implements RequestBodyAdvice {
//是否对请求拦截处理(根据实际情况可以写在配置文件中)
private Boolean enable = true;
//密钥(根据实际情况可以写在配置文件中)
private final static String encryptKey = "abdel99999999";
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
log.info("【进入-RequestBody-supports】");
//是否开启拦截
if(!enable.equals(true)) {
return false;
}
//排除get请求
if(methodParameter.hasMethodAnnotation(GetMapping.class)) {
return false;
}
return true;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
log.info("【进入-RequestBody-beforeBodyRead】");
log.info("【拦截到的请求参数为:】" + inputMessage.toString());
String s = null;
String requestBodyStr = getRequestBodyStr(inputMessage.getBody());
requestBodyStr = requestBodyStr.replaceAll("\\r\\n", "");
JSONObject jsonObject = JSONObject.parseObject(requestBodyStr);
String inputStr = jsonObject.getString("inputStr");
try {
s = EncrpytUtils.decryptDES(inputStr, encryptKey);
} catch (Exception e) {
e.printStackTrace();
}
// 使用解密后的数据,构造新的读取流
InputStream rawInputStream = new ByteArrayInputStream(s.getBytes());
return new HttpInputMessage() {
@Override
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
@Override
public InputStream getBody() throws IOException {
return rawInputStream;
}
};
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
log.info("【进入-RequestBody-afterBodyRead】");
return body;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
log.info("【进入-RequestBody-handleEmptyBody】");
return null;
}
/**
* reuqest body流数据转换为String
* @param inputStream
* @return
* @throws IOException
*/
public static String getRequestBodyStr(InputStream inputStream) throws IOException {
StringBuilder builder = new StringBuilder();
if (!ObjectUtils.isEmpty(inputStream)) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
builder.append(charBuffer, 0, bytesRead);
}
}else {
builder.append("");
}
return builder.toString();
}
}
自定义responseBody拦截器
/**
* 它允许在 执行 @ResponseBody后自定义返回数据,或者将返回@ResponseEntity的 Controller Method在写入主体前使用HttpMessageConverter进行自定义操作。
* 由此可见,它的作用范围为:使用@ResponseBody注解进行标记 返回@ResponseEntity
*
*/
@RestControllerAdvice
@Slf4j
public class ResponseBody implements ResponseBodyAdvice {
//是否对返回拦截处理
private Boolean enable = true;
private final static String encryptKey = "abdel99999999";
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
log.info("【进入-ResponseBody-supports】");
if(enable.equals(true)) {
return true;
}
return false;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
log.info("【进入-ResponseBody-beforeBodyWrite】");
if(body == null) {
return null;
}
String str;
try {
if(body instanceof String) {
str = (String) body;
}else {
str = JSON.toJSONString(body);
}
String s = EncrpytUtils.encryptDES(str, encryptKey);
log.info("【加密之后的数据:】" + s);
return s.replaceAll("\\r\\n", "").replaceAll("\\n", "").replaceAll("\\r", "");
} catch (Exception e) {
e.printStackTrace();
log.info("【ResponseBody加密处理异常】");
return "";
}
}
}
EncrpytUtils工具类
public class EncrpytUtils {
/**
* DES加密算法
*/
public final static String ALGORITHM_DES = "DES";
/**
* 加密字符串(Java 8提供的Base64,要比sun.misc套件提供的还要快至少11倍,比Apache Commons Codec提供的还要快至少3倍)
*
* @param code 需要加密的字符串
* @param encryptKey 对称密钥串
* @throws Exception
*/
public static String encryptDES(String code, String encryptKey) throws Exception {
//java8提供的类(Base64)
Base64.Encoder encoder = Base64.getEncoder();
byte[] bytesMing = encryptDES(code.getBytes("UTF8"), encryptKey);
return encoder.encodeToString(bytesMing);
}
/**
* 解密字符串(Java 8提供的Base64,要比sun.misc套件提供的还要快至少11倍,比Apache Commons Codec提供的还要快至少3倍)
*
* @param code 需要解密的字符串1
* @param encryptKey 对称密钥串
* @throws Exception
*/
public static String decryptDES(String code, String encryptKey) throws Exception {
//java8提供的类(Base64)
Base64.Decoder decoder = Base64.getDecoder();
byte[] decode = decoder.decode(code);
byte[] bytesMing = decryptDES(decode, encryptKey);
return new String(bytesMing, "UTF8");
}
/**
* 加密
*
* @param bytes 明文字节
* @param encryptKey 对称密钥串
* @throws Exception
*/
public static byte[] encryptDES(byte[] bytes, String encryptKey) throws Exception {
Key key = generateKey(encryptKey);
Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(bytes);
}
/**
* 生成密钥
*
* @param encryptKey
* @throws Exception
*/
public static Key generateKey(String encryptKey) throws Exception {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM_DES);
DESKeySpec keySpec = new DESKeySpec(encryptKey.getBytes());
return keyFactory.generateSecret(keySpec);
}
/**
* 解密
*
* @param bytes 密文字节
* @param encryptKey 对称密钥串
* @throws Exception
*/
public static byte[] decryptDES(byte[] bytes, String encryptKey) throws Exception {
Key key = generateKey(encryptKey);
Cipher cipher = Cipher.getInstance(ALGORITHM_DES);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(bytes);
}
/**
* 方便测试(正常情况下是前端加密请求参数,后端接收到请求参数进行解密操作,执行完逻辑之后,对返回的数据进行加密返回给前端,前端解密获取数据)
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String test="{\"name\":\"1243\",\"age\":\"18\"}";
String s = encryptDES(test, "abdel99999999");
System.out.println("【加密之后数据:】" + s.replaceAll("\\r\\n",""));
String a = "ERt7/Jenk6IUXqQ8lThdSC2/pa4ok2zHi00WmsZ/ejZSBl5tue0xPfom0lbznugFaKaS4U+CeK4qkzL58umRIkw2uBDKl/QvDbfK0povrUDmiCK2cbQmHvxSHl8eZNE/kWguLmPTBCkx4ukluDOfn5dRdovc6LmOnv+sH6SqSXT+8N8h5e3133LvQcxMeHJ5/fyJPfdUfomEcxrLkNIGRtZR/nJiGUNAxYRx0d6Ol2ziMB3rl9dwtlUg1h3WpbIQK13EsXK7yw6wIyGKYDJfZQ5y90MQTwJQ/fyJPfdUfolGgy60lKNvaNZR/nJiGUNAxYRx0d6Ol2xRbjUCuWOkkFUg1h3WpbIQK13EsXK7yw7/kUPCnnTkRjcqbJLsbi41qBXecwZ1295++KkaKFumbofsH9AUO0gLcmjVpmv6SJBJsK/B2mRK6ChA58AnNW9uBRzQiJwiy561MBtbId9rmCLjSw6YlZ6G3rAyZzJoMAhqph64pt+tc8/lZIUBWbhJobvpPD2Hf+kWIEVwFyfr2kF21rnbnxfi/FIeXx5k0T+RaC4uY9MEKZ46K/zylLpFKpot8yn1beN9kxRgMNlTmW4QresvktoCSF+qR1TXar+iWfnLPWVGxreTiMK95aJ0Ot2elSE/rkInJ+Po1xyN4knc4Ro5qgUr/IUM6wtDH0qbekH7+wN2kp0qMUJpq5Uh7R/2BqiMtIVDLRYyOzDFPFQV7RfRS/nvrOVAPRoTBNU8jkYiu5zbX5zdwnvHItKMK13EsXK7yw5SicWOT56KI4tM88TA0H8okvuh5K58C5JKGr5N8IDenKFUOmuvE6ATH3vHYZ8N92oo6+8QlEUPY6rihsJYMB8/77XN5L2c484=";
String aa = decryptDES(a, "abdel99999999");
System.out.println("【解密之后数据:】" + aa);
}
}
controller层
@RequestMapping("user")
@RestController
@Slf4j
public class UserController {
@PostMapping("selectUser2")
public Object selectUser2(@RequestBody User user) {
String s = JSON.toJSONString(user);
System.out.println(s);
log.info("【接收到的请求参数:】" + s);
return "成功的返回数据了";
}
}