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)); } }

 

posted @ 2021-09-15 15:07  CodingPanda  阅读(808)  评论(0编辑  收藏  举报