实现RequestBodyAdvice接口实现解密
允许在请求消息体在被读取及调用convert转换成实体之前做一些个人化操作,
作用于含有@RequestBody注解的请求。
实现此接口的类,需要在RequestMappingHandlerAdapter中配置或通过@ControllerAdvice注解配置。
实现ResponseBodyAdvice接口实现加密
在消息转换前处理返回值
我们实现这个接口的代码主要在这个方法里被调用
RequestResponseBodyAdviceChain.processBody,
先执行ResponseBodyAdvice.supports看当前切面类是否支持,
如果支持再调用ResponseBodyAdvice.beforeBodyWrite方法并返回
返回值会被HttpMessageConverter.write接口在进行最终的转换(例如转JSON)
然后写回前端
链接: SpringMVC进阶 – 利用@ControllerAdvice和ResponseBodyAdvice接口统一处理返回值.
链接: SpringMvc/SpringBoot HTTP通信加解密.
链接: SpringBoot 请求消息体解密(通信加密解密).
链接: 加解密测试网站.
链接: 对称加密-SymmetricCrypto.
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.49</version>
</dependency>
</dependencies>
import java.io.Serializable;
public class ApiResult<T> implements Serializable {
private T data;
private int code;
private String msg;
/**
* 请求成功回调
*/
public static ApiResult successMsg() {
return new ApiResult().setCode(200).setMsg("ok");
}
/**
* 请求成功回调
* @param Object 对象参数
*/
public static ApiResult successMsg(Object Object) {
return new ApiResult().setCode(200).setMsg("ok").setData(Object);
}
/**
* 请求失败回调
* @param code 状态码
* @param msg 描述信息
*/
public static ApiResult errorMsg(int code, String msg) {
return new ApiResult().setCode(code).setMsg(msg);
}
/**
* 请求失败回调
* @param msg 描述信息
*/
public static ApiResult errorMsg(String msg) {
return new ApiResult().setCode(500).setMsg(msg);
}
public T getData() {
return data;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
public ApiResult<T> setData(T data) {
this.data = data;
return this;
}
public ApiResult<T> setCode(Integer code) {
this.code = code;
return this;
}
public ApiResult<T> setMsg(String msg) {
this.msg = msg;
return this;
}
}
import lombok.Data;
@Data
public class TestReq {
private String name;
}
TestController
import com.zm.config.SecretBody;
import com.zm.config.SecretResponseBody;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
//@SecretBody // 作用全部类
@RestController
public class TestController {
@SecretResponseBody
@SecretBody // 作用当前类
@PostMapping("test")
public ApiResult test1(@RequestBody TestReq testReq){
System.out.println(testReq);
return ApiResult.successMsg(testReq);
}
@GetMapping("test")
public ApiResult test2(@RequestBody TestReq testReq){
System.out.println(testReq);
return ApiResult.successMsg(testReq);
}
}
请求体解密注解
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 SecretBody {
}
响应体加密注解
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 SecretResponseBody {
}
Des工具类
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.DES;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class DesCbcUtil {
private final String DES_SECRET_KEY = "b2c17b46e2b1415392aab5a82869856c";
private final String DES_IV = "61960842";
private DES des = new DES(Mode.CBC, Padding.PKCS5Padding, DES_SECRET_KEY.getBytes(), DES_IV.getBytes());
/**
* 3DES加密
*
* @param plainText 普通文本
* @return 加密后的文本,失败返回null
*/
public String encode(String plainText) {
String result = null;
try {
result = des.encryptBase64(plainText);
} catch (Exception e) {
log.error("DesCbcUtil encode error : {}", e);
}
return result;
}
/**
* 3DES解密
*
* @param encryptText 加密文本
* @return 解密后明文,失败返回null
*/
public String decode(String encryptText) {
String result = null;
try {
result = des.decryptStr(encryptText);
} catch (Exception e) {
log.error("DesCbcUtil decode error : {}", e.getMessage());
}
return result;
}
}
SecretHttpMessage
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import java.io.InputStream;
@AllArgsConstructor
@NoArgsConstructor
public class SecretHttpMessage implements HttpInputMessage {
private InputStream body;
private HttpHeaders httpHeaders;
@Override
public InputStream getBody() {
return this.body;
}
@Override
public HttpHeaders getHeaders() {
return this.httpHeaders;
}
}
接收前端请求体解密
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.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
@Slf4j
@ControllerAdvice
@Order(1)
public class SecretRequestAdvice implements RequestBodyAdvice {
@Autowired
private DesCbcUtil DesCbcUtil;
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
//如果支持加密消息,进行消息解密。
boolean supportSafeMessage = supportSecretRequest(parameter);
String httpBody;
if (supportSafeMessage) {
// 拓展:可以根据注解设置的参数,进行不同解密方式的选择
httpBody = decryptBody(inputMessage);
if (httpBody == null) {
throw new HttpMessageNotReadableException("request body decrypt error", inputMessage);
}
} else {
httpBody = StreamUtils.copyToString(inputMessage.getBody(), Charset.defaultCharset());
}
//返回处理后的消息体给messageConvert
return new SecretHttpMessage(new ByteArrayInputStream(httpBody.getBytes()), inputMessage.getHeaders());
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
/**
* 是否支持加密消息体
*
* @param methodParameter methodParameter
* @return true/false
*/
private boolean supportSecretRequest(MethodParameter methodParameter) {
//判断class是否存在注解
if (methodParameter.getContainingClass().getAnnotation(SecretBody.class) != null) {
return true;
}
//判断方法是否存在注解
return methodParameter.getMethodAnnotation(SecretBody.class) != null;
}
/**
* 解密消息体,3des解析(cbc模式)
*
* @param inputMessage 消息体
* @return 明文
*/
private String decryptBody(HttpInputMessage inputMessage) throws IOException {
InputStream encryptStream = inputMessage.getBody();
String encryptBody = StreamUtils.copyToString(encryptStream, Charset.defaultCharset());
return DesCbcUtil.decode(encryptBody);
}
}
返回前端响应体加密
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@Slf4j
@Component
@ControllerAdvice(basePackages = "com.zm.controller")
public class SecretResponseAdvice implements ResponseBodyAdvice {
@Autowired
DesCbcUtil desCbcUtil;
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return returnType.getMethodAnnotation(SecretResponseBody.class) != null;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (returnType.getMethodAnnotation(SecretResponseBody.class) != null) {
// 拓展:可以根据注解设置的参数,进行不同加密方式的选择
String encode = desCbcUtil.encode(JSON.toJSONString(body));
return encode;
}
return body;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/133927.html