Spring Cloud网关使用GlobalFilter过滤器做参数防篡改
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)); } }