package com.lll.serviceoutgateway.appCode;
import com.lll.serviceoutgateway.appCode.util.SHA256Util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import io.netty.buffer.ByteBufAllocator;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
/**
* 防篡改过滤器
*
* @author: lll
* @date: 2021年08月27日 14:08:20
*/
@Component
public class TamperProofFilter implements GlobalFilter, Ordered {
static Logger logger = LoggerFactory.getLogger(TamperProofFilter.class);
//加密key
private static final String enCodeKey = "CodingPanda";
@SneakyThrows
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest serverHttpRequest = exchange.getRequest();
HttpMethod method = serverHttpRequest.getMethod();
String checkTamper = serverHttpRequest.getHeaders().getFirst("checkTamper");
//checkTamper为1时才进行防篡改校验
if (checkTamper != null && "1".equals(checkTamper)) {
//时间戳
String timestamp = serverHttpRequest.getHeaders().getFirst("timestamp");
//校验时间:服务器时间和请求时间相差超过60秒,校验不通过
Long timeCheck = (System.currentTimeMillis() - Long.valueOf(timestamp)) / (1000);
if (timeCheck >= 60) {
logger.info("Current Time Stamp: " + (System.currentTimeMillis()) / (1000));
logger.info("timestamp: " + (System.currentTimeMillis()) / (1000));
Map<String, Object> responseData = Maps.newHashMap();
responseData.put("code", 406);
responseData.put("msg", "对不起,防篡改校验未通过,请求失败!");
ObjectMapper objectMapper = new ObjectMapper();
byte[] data = new byte[0];
try {
data = objectMapper.writeValueAsBytes(responseData);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
ServerHttpResponse res = exchange.getResponse();
DataBuffer buffer = res.bufferFactory().wrap(data);
res.setStatusCode(HttpStatus.OK);
res.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return res.writeWith(Mono.just(buffer));
}
//校验串
String checkTamperSign = serverHttpRequest.getHeaders().getFirst("checkTamperSign");
//参数
String params = "";
String bodyStr = "";
if (method == HttpMethod.POST || method == HttpMethod.PUT) {
//从请求里获取Post请求体
bodyStr = resolveBodyFromRequest(serverHttpRequest);
params = bodyStr;
logger.info("PUT OR POST params: " + params);
} else if (method == HttpMethod.GET || method == HttpMethod.DELETE) {
MultiValueMap<String, String> requestQueryParams = serverHttpRequest.getQueryParams();
params = requestQueryParamsToString(requestQueryParams);
logger.info("GET OR DELETE ciphertext parameters: " + params);
}
//截取前32为长度
if (params.length() > 32) {
params = params.substring(0, 31);
}
//校验
String plain = params + enCodeKey + timestamp;
String cipher = SHA256Util.getSHA256(plain);
logger.info("plain: " + plain);
logger.info("cipher: " + cipher);
logger.info("checkTamperSign: " + checkTamperSign);
if (!cipher.equals(checkTamperSign)) {
Map<String, Object> responseData = Maps.newHashMap();
responseData.put("code", 406);
responseData.put("msg", "对不起,防篡改校验未通过,请求失败!");
ObjectMapper objectMapper = new ObjectMapper();
byte[] data = new byte[0];
try {
data = objectMapper.writeValueAsBytes(responseData);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
ServerHttpResponse res = exchange.getResponse();
DataBuffer buffer = res.bufferFactory().wrap(data);
res.setStatusCode(HttpStatus.OK);
res.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return res.writeWith(Mono.just(buffer));
} else {
//post请求的body需要解析之后再次封装,否则请求会报错
if (params != null && (method == HttpMethod.POST || method == HttpMethod.PUT )) {
logger.info("PUT OR POST bodyStr: " + bodyStr);
URI uri = serverHttpRequest.getURI();
ServerHttpRequest request = serverHttpRequest.mutate().uri(uri).build();
DataBuffer bodyDataBuffer = stringBuffer(bodyStr);
Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
request = new ServerHttpRequestDecorator(request) {
@Override
public Flux<DataBuffer> getBody() {
return bodyFlux;
}
};
return chain.filter(exchange.mutate().request(request).build());
}
}
}
return chain.filter(exchange);
}
private DataBuffer stringBuffer(String value) {
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
buffer.write(bytes);
return buffer;
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 4;
}
//将Map参数拼接位字符串
private String requestQueryParamsToString(MultiValueMap<String, String> requestQueryParams) {
List<String> paramsArray = new ArrayList<String>();
for (String key : requestQueryParams.keySet()) {
String temp = key + "=" + requestQueryParams.get(key).get(0);
paramsArray.add(temp);
}
String params = "";
for (int i = 0; i < paramsArray.size(); i++) {
if (i == paramsArray.size() - 1) {
params = params + paramsArray.get(i);
} else {
params = params + paramsArray.get(i) + "&";
}
}
return params;
}
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
//获取请求体
Flux<DataBuffer> body = serverHttpRequest.getBody();
AtomicReference<String> bodyRef = new AtomicReference<>();
body.subscribe(buffer -> {
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
DataBufferUtils.release(buffer);
bodyRef.set(charBuffer.toString());
});
//获取request body
return bodyRef.get();
}
public static void main(String[] args) {
Long datetime = System.currentTimeMillis();
Timestamp timestamp = new Timestamp(datetime);
String params = "{\"pageSize\":10,\"pageNo\":1,\"mlmc\":\"\",\"lmId\":\"02020072909122290800000101001101\",\"gxzq\":[],\"mlzt\":[],\"kflx\":[],\"zylx\":[]}";
params = params.substring(0, 31);
logger.info(params);
logger.info("Current Time Stamp: " + datetime);
logger.info(params + enCodeKey + datetime);
logger.info(SHA256Util.getSHA256(params + enCodeKey + datetime));
}
}