验签 加密
@Slf4j
@ControllerAdvice(basePackages = "cn.com.sgcc.sgec.ksplatform.module.emelt.app.controller")
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
@Value("${app.keys.privateKey}")
private String privateKey;
@Value("${app.encryption}")
private boolean encryption;
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return methodParameter.hasParameterAnnotation(RequestBody.class);
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
return new DecryptHttpInputMessage(inputMessage);
}
@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;
}
private class DecryptHttpInputMessage implements HttpInputMessage {
private HttpInputMessage inputMessage;
public DecryptHttpInputMessage(HttpInputMessage inputMessage) {
this.inputMessage = inputMessage;
}
@Override
public InputStream getBody() throws IOException {
InputStream input = inputMessage.getBody();
String body = IOUtils.toString(input, "UTF-8");
log.info("请求参数:"+body);
ItemRequest request = JSONUtil.toBean(JSONUtil.parseObj(body), ItemRequest.class);
if(!encryption){
return IOUtils.toInputStream(JSONUtil.toJsonStr(request.getRaw()),"UTF-8");
}
log.debug("raw:{}",request.getRaw());
log.debug("time:{}",request.getTime().getTime());
String hashData = request.getRaw().toString()+request.getTime().getTime();
String hash = SmUtil.sm3(hashData);
log.debug("sm3 hash:{}",hash);
if(!request.getHash().equals(hash)){
log.error("数据签名不一致,您的数据可能被篡改");
throw new KsException("数据签名不一致,您的数据可能被篡改");
}
String token = request.getToken();
RSA rsa = new RSA(privateKey,null);
String key = rsa.decryptStr(token, KeyType.PrivateKey);
log.debug("key:{}",key);
SymmetricCrypto sm4 = SmUtil.sm4(key.getBytes());
String raw = sm4.decryptStr(request.getRaw().toString());
log.debug("raw:{}",raw);
return IOUtils.toInputStream(JSONUtil.toJsonStr(raw),"UTF-8");
}
@Override
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
}
ItemRequest 类
@Data
@Slf4j
public class ItemRequest implements Serializable{
private static final long serialVersionUID = -1441518635151006789L;
private Date time;
private Object raw;
private String hash;
private String token;
public <E> E toBean(Class<E> clazz){
try {
return (E) JSONUtil.toBean(JSONUtil.parseObj(this.getRaw()), clazz);
} catch (Exception e) {
log.error("无法转换对象,{},{}",clazz.getSimpleName(),e.getMessage());
}
return null;
}
public Map<String, Object> toMap(){
return toBean(HashMap.class);
}
}
统一添加签名
@Slf4j
@ControllerAdvice(basePackages = "cn.com.sgcc.sgec.ksplatform.module.emelt.app.controller")
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice {
@Value("${app.keys.publicKey}")
private String publicKey;
@Value("${app.encryption}")
private boolean encryption;
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if(!encryption || !(body instanceof AppItemResponse)){
return body;
}
return encodeBody(body);
}
private Object encodeBody(Object object){
AppItemResponse itemResponse = (AppItemResponse) object;
Object data = itemResponse.getData();
String key = RandomUtil.randomString(16);
String jsonData = null;
if(data != null){
jsonData = JSONObject.toJSONString(data);
log.debug("response jsonData:{}",jsonData);
}
SymmetricCrypto sm4 = SmUtil.sm4(key.getBytes());
String encryptionData = sm4.encryptHex(jsonData);
RSA rsa = new RSA(null,publicKey);
String token = rsa.encryptBase64(key, KeyType.PublicKey);
long time = DateUtil.current(false);
String hashData = encryptionData+time;
String hash = SmUtil.sm3(hashData);
itemResponse.setHash(hash);
itemResponse.setTime(time);
itemResponse.setToken(token);
itemResponse.setData(encryptionData);
log.debug("response key:{},hash:{},time:{},token:{},data:{}",key,hash,time,token,encryptionData);
return itemResponse;
}
}
AppItemResponse 类
@Data
@EqualsAndHashCode(callSuper = false)
public class AppItemResponse<T> implements Serializable{
private static final long serialVersionUID = -5096367565578119351L;
private long time;
private T data;
private String hash;
private String token;
private String msg;
private String status;
private AppItemResponse(T data){
this.time = new Date().getTime();
this.data = data;
}
protected AppItemResponse(){
}
public static <T> AppItemResponse success(T data) {
AppItemResponse<T> ir = new AppItemResponse<>(data);
ir.status = ResponseCodeConstant.OK;
return ir;
}
public static <T> AppItemResponse success(String msg, T data) {
AppItemResponse<T> ir = new AppItemResponse<>(data);
ir.status = ResponseCodeConstant.OK;
ir.msg = msg;
return ir;
}
public static <T> AppItemResponse fault(String msg) {
AppItemResponse<T> ir = new AppItemResponse<>();
ir.setMsg(msg);
ir.status = ResponseCodeConstant.ERROR;
return ir;
}
public static <T> AppItemResponse create(T data, String status) {
AppItemResponse<T> ir = new AppItemResponse<>(data);
ir.status = status;
return ir;
}
public String toJsonStr(){
return JSONUtil.toJsonStr(this);
}
public boolean success(){
return StringUtils.equalsIgnoreCase(ResponseCodeConstant.OK,status);
}
}