tech.mhuang.pacebox.springboot.autoconfiguration.datasecure.advice.DataSecureRequestBodyAdvice Maven / Gradle / Ivy
package tech.mhuang.pacebox.springboot.autoconfiguration.datasecure.advice;
import com.alibaba.fastjson2.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
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.RequestBodyAdviceAdapter;
import tech.mhuang.pacebox.core.exception.BusinessException;
import tech.mhuang.pacebox.core.io.IOUtil;
import tech.mhuang.pacebox.core.util.ObjectUtil;
import tech.mhuang.pacebox.core.util.StringUtil;
import tech.mhuang.pacebox.springboot.autoconfiguration.datasecure.DataSecureInfo;
import tech.mhuang.pacebox.springboot.autoconfiguration.datasecure.DataSecureProperties;
import tech.mhuang.pacebox.springboot.autoconfiguration.datasecure.annation.DataSecureField;
import tech.mhuang.pacebox.springboot.autoconfiguration.datasecure.annation.DecryptMapping;
import tech.mhuang.pacebox.springboot.autoconfiguration.datasecure.consts.DecryptType;
import tech.mhuang.pacebox.springboot.core.spring.util.DataUtil;
import tech.mhuang.pacebox.springboot.protocol.Result;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Objects;
/**
* 请求数据解密
*
* @author mhuang
* @since 1.0.0
*/
@ControllerAdvice
public class DataSecureRequestBodyAdvice extends RequestBodyAdviceAdapter {
private final DataSecureProperties secretProperties;
public DataSecureRequestBodyAdvice(DataSecureProperties properties) {
this.secretProperties = properties;
}
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class extends HttpMessageConverter>> aClass) {
return Objects.requireNonNull(methodParameter.getMethod()).isAnnotationPresent(DecryptMapping.class) ||
methodParameter.getContainingClass().isAnnotationPresent(DecryptMapping.class);
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class extends HttpMessageConverter>> aClass) throws IOException {
DecryptMapping decryptMapping = Objects.requireNonNull(methodParameter.getMethod()).getAnnotation(DecryptMapping.class);
if (ObjectUtil.isEmpty(decryptMapping)) {
decryptMapping = methodParameter.getContainingClass().getAnnotation(DecryptMapping.class);
}
//获取配置项
DataSecureInfo dataSecureInfo;
String configKey = decryptMapping.value();
if (StringUtil.isEmpty(configKey)) {
dataSecureInfo = secretProperties;
} else if (secretProperties.getDataSecurePropertiesMap().containsKey(configKey)) {
dataSecureInfo = secretProperties.getDataSecurePropertiesMap().get(configKey);
} else {
throw new BusinessException(Result.SYS_FAILD, String.format("找不到配置项:%s", configKey));
}
//应答数据
String httpBody;
//整体解密
if (decryptMapping.type() == DecryptType.ALL) {
httpBody = decryptBody(httpInputMessage, dataSecureInfo);
} else {
//字段解密
Field[] fields = methodParameter.getParameter().getType().getDeclaredFields();
Object entity = JSON.parseObject(toString(httpInputMessage, dataSecureInfo), type);
for (Field field : fields) {
//需要处理的字段
if (field.isAnnotationPresent(DataSecureField.class)) {
DataSecureField dataSecureField = field.getAnnotation(DataSecureField.class);
try {
Object proceeFieldValue = DataUtil.getValueByModelKey(entity, field.getName(), field.getType());
if (dataSecureField.decode() && ObjectUtil.isNotEmpty(proceeFieldValue)) {
DataUtil.setValueByModel(entity, field.getName(), dataSecureField.Clazz().getDeclaredConstructor().newInstance().decrypt(
proceeFieldValue instanceof String ? (String) proceeFieldValue : JSON.toJSONString(proceeFieldValue),
dataSecureInfo.getPrivateKey()
));
}
} catch (Exception e) {
throw new BusinessException(Result.SYS_FAILD, "处理字段异常", e);
}
}
}
httpBody = JSON.toJSONString(entity);
}
return new DataSecureHttpMessage(new ByteArrayInputStream(httpBody.getBytes()), httpInputMessage.getHeaders());
}
private String decryptBody(HttpInputMessage httpInputMessage, DataSecureInfo dataSecureInfo) throws IOException {
String encryptBody = toString(httpInputMessage, dataSecureInfo);
try {
return dataSecureInfo.getEncryptDataInterface().getDeclaredConstructor().newInstance().decrypt(encryptBody, dataSecureInfo.getPrivateKey());
} catch (Exception e) {
throw new BusinessException(Result.SYS_FAILD, "数据解密异常", e);
}
}
private String toString(HttpInputMessage httpInputMessage, DataSecureInfo dataSecureInfo) throws IOException {
InputStream encryptStream = httpInputMessage.getBody();
try {
return IOUtil.toString(encryptStream, dataSecureInfo.getEncryptDataInterface().getDeclaredConstructor().newInstance().getDecryptCoding().toString());
} catch (Exception e) {
throw new BusinessException(Result.SYS_FAILD, "数据解密异常", e);
}
}
@Data
@AllArgsConstructor
static
class DataSecureHttpMessage implements HttpInputMessage {
private InputStream body;
private HttpHeaders httpHeaders;
@Override
public InputStream getBody() {
return this.body;
}
@Override
public HttpHeaders getHeaders() {
return this.httpHeaders;
}
}
}