瀏覽代碼

feat:后端项目,API网关模块,自定义全局过滤器,全局统一的日志,全局统一的参数校验,全局统一的接口鉴权

yang yi 10 月之前
父節點
當前提交
a066f93ef3
共有 1 個文件被更改,包括 107 次插入0 次删除
  1. 107 0
      open-api-gateway/src/main/java/space/anyi/openAPIGateway/filter/ConsumerFilter.java

+ 107 - 0
open-api-gateway/src/main/java/space/anyi/openAPIGateway/filter/ConsumerFilter.java

@@ -0,0 +1,107 @@
+package space.anyi.openAPIGateway.filter;
+
+import org.reactivestreams.Publisher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+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.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.RequestPath;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.CoreSubscriber;
+import reactor.core.publisher.Mono;
+
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+
+/**
+ * @ProjectName: open-api-gateway
+ * @FileName: GlobalFilter
+ * @Author: 杨逸
+ * @Data:2025/11/20 11:08
+ * @Description: 局部过滤器
+ * 只对openAPI接口路由进行过滤处理
+ */
+@Component()
+public class ConsumerFilter implements GlobalFilter, Ordered {
+    /**
+     * todo:自定义局部过滤器
+     * 自定义的过滤器名称规则:后缀一定要是GatewayFilterFactory
+     * 在配置文件配置自定义过滤器时只需要配置name为Consumer即可
+     */
+    public static final Logger log = LoggerFactory.getLogger(ConsumerFilter.class);
+    /**
+     * 记录时间戳和随机数nonce(防止重放攻击)
+     * @see Set<String>
+     */
+    public static final Set<String> timestampAndNonceSet = new HashSet<>();
+    @Override
+    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+        ServerHttpRequest request = exchange.getRequest();
+        ServerHttpResponse response = exchange.getResponse();
+        HttpHeaders headers = request.getHeaders();
+        RequestPath url = request.getPath();
+        log.debug("url:{}", url);
+        String accessKey = headers.getFirst("accessKey");
+        log.debug("accessKey:{}", accessKey);
+        String timestamp = headers.getFirst("timestamp");
+        log.debug("timestamp:{}", timestamp);
+        String sign = headers.getFirst("sign");
+        log.debug("sign:{}", sign);
+        String nonce = headers.getFirst("nonce");
+        log.debug("nonce:{}", nonce);
+        //校验时间
+        try {
+            long five_minutes = 5 * 60 * 1000;
+            if (Objects.isNull(timestamp) || five_minutes < Math.abs(System.currentTimeMillis() - Long.valueOf(timestamp))) {
+                log.warn("时间戳{}不合法", timestamp);
+                return parameterExceptionHandler(response,"时间戳不合法");
+            }
+        } catch (NumberFormatException e) {
+            e.printStackTrace();
+            log.error("时间戳转换失败",e);
+        }
+        //随机数nonce校验
+        if (Objects.isNull(nonce) || timestampAndNonceSet.contains(timestamp + nonce)) {
+            log.warn("随机数{}不合法", nonce);
+            return parameterExceptionHandler(response,"随机数不合法");
+        }
+        timestampAndNonceSet.add(timestamp + nonce);
+        //todo:检查接口是否存在并且开通调用
+        //todo:是否还有调用次数
+        //todo:校验accessKey和secretKey
+
+        return chain.filter(exchange).then(new Mono<Void>() {
+            @Override
+            public void subscribe(CoreSubscriber<? super Void> actual) {
+                //todo:过滤器后置处理
+                log.info("过滤器后置处理");
+            }
+        });
+    }
+
+    private Mono<Void> parameterExceptionHandler(ServerHttpResponse response, String msg) {
+        response.writeAndFlushWith(new Mono<Publisher<? extends DataBuffer>>() {
+            @Override
+            public void subscribe(CoreSubscriber<? super Publisher<? extends DataBuffer>> actual) {
+                actual.onNext(Mono.just(response.bufferFactory().wrap(msg.getBytes())));
+            }
+        });
+        response.setStatusCode(HttpStatus.BAD_REQUEST);
+        return response.setComplete();
+    }
+
+    @Override
+    public int getOrder() {
+        return 0;
+    }
+}