欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

spring-gateway filters添加自定義過濾器實現(xiàn)流程分析(可插拔)

 更新時間:2025年05月28日 10:43:53   作者:木子李的Z  
這篇文章主要介紹了spring-gateway filters添加自定義過濾器實現(xiàn)流程分析(可插拔),本文通過實例圖文相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧

需求背景

公司要求,通過公司網絡代理訪問的請求需要做請求隔離,即,通過特定代理IP訪問的請求,需要除正常權限以外,還需要對請求路徑,及特定路徑下的請求參數(shù)做校驗,通過校驗正常訪問,否則拒絕通過代理IP的請求。

需求拆解

1.針對特定的服務做限制;

2.特定的代理IP來源請求做校驗;

3.特定的請求接口做限制;

4.特定的接口的特定的請求參數(shù)值做校驗;

大致可以細分如上四點,在網關層統(tǒng)一實現(xiàn)需求,參考spring-gateway過濾器原理,個性化一個過濾器,按需配置即可;

設計流程及作用域

在配置網關路由策略時按需配置,靈活使用。

圖2.1過濾器位置

自定義過濾器名稱:InternalValidator

2.2spring-gateway使用配置示例

過濾器設計

1.name : InternalValidator 過濾器id (必須)

2.args : 過濾器參數(shù) (個性化實現(xiàn)時必須)

2.1 paths: /api/**,/** 請求路徑校驗(通配符),前提條件1

2.2 limited-from: '172.24.173.62,172.24.172.252' 模擬代理IP地址,前提條件2

2.3 conditions: 條件過濾,這是個個性化配置集合

2.3.1 paths: /api/** 條件集合判斷路徑校驗(通配符)

2.3.2 body-param: 'code' 請求體參數(shù)名{'code':'159300'}

2.3.3 body-value:'159300' 參數(shù)名對應的參數(shù)值

2.3.4 path-param: 'name' 路徑參數(shù)名 ?name=zhangsan

2.3.5 path-value: 'zhangsan' 路徑參數(shù)值 

3.excludes:'/api/login/*' 排除路徑(通配符)

邏輯處理

1.來自代理IP判斷

3.1邏輯處理

邏輯流程

3.2流程處理

代碼邏輯

1.名稱必須是InternalValidator + GatewayFilterFactory

2.config服從駝峰命名轉換 即limited-from : limitedFrom

3.對config映射屬性必須要有set方法

@Component
@Slf4j
public class InternalValidatorGatewayFilterFactory extends AbstractGatewayFilterFactory<InternalValidatorGatewayFilterFactory.Config> implements Ordered {
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    public InternalValidatorGatewayFilterFactory() {
        super(Config.class); // 指定配置類
    }
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            Set<String> limitedIps = config.getLimitedIps();
            ServerHttpRequest request = exchange.getRequest();
            //接口路徑
            String clientIp = IPHelp.getClientIp(request);
            if (!isLimitedIp(clientIp, limitedIps)) {
                return chain.filter(exchange);
            }
            String path = request.getPath().value();
            Set<String> includesPaths = config.getIncludesPaths();
            if (!pathMatch(path, includesPaths)) {
                log.info(" --> includesPaths: {}, 不包含: 請求路徑:{},", includesPaths, path);
                return chain.filter(exchange);
            }
            Set<String> excludesPaths = config.getExcludesPaths();
            if (pathMatch(path, excludesPaths)) {
                log.info(" --> excludesPaths: {}, contains: 請求路徑:{},", excludesPaths, path);
                return chain.filter(exchange);
            }
            Map<String, Map<String, String>> pathParamValueMap = config.getPathParamValueMap();
            Map<String, Map<String, String>> bodyParamValueMap = config.getBodyParamValueMap();
            Map<String, String> bodyParamMap = getPathParamValueMap(path, bodyParamValueMap);
            Map<String, String> queryParamMap = getPathParamValueMap(path, pathParamValueMap);
            if ((bodyParamMap == null || bodyParamMap.isEmpty()) && (
                    queryParamMap == null || queryParamMap.isEmpty()
            )) {
                exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                return exchange.getResponse().setComplete();
            }
            if (queryParamMap != null && !queryParamMap.isEmpty()) {
                MultiValueMap<String, String> queryParams = request.getQueryParams();
                if (!queryParamMatch(queryParamMap, queryParams)) {
                    log.info(" --> path: {}, bodyParamConditions: {}, queryParamMap: {},校驗失??!", path, bodyParamMap, queryParamMap);
                    exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                    return exchange.getResponse().setComplete();
                }
                if (bodyParamMap == null || bodyParamMap.isEmpty()) {
                    return chain.filter(exchange);
                }
            }
            if (bodyParamMap != null && !bodyParamMap.isEmpty()) {
                String method = request.getMethodValue();
                if ("POST".equals(method)) {
                    return DataBufferUtils.join(exchange.getRequest().getBody())
                            .flatMap(dataBuffer -> {
                                byte[] bytes = new byte[dataBuffer.readableByteCount()];
                                dataBuffer.read(bytes);
                                try {
                                    String bodyString = new String(bytes, "utf-8");
                                    if (!bodyParamMatch(bodyParamMap, bodyString)) {
                                        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                                        return exchange.getResponse().setComplete();
                                    }
                                } catch (UnsupportedEncodingException e) {
                                }
                                DataBufferUtils.release(dataBuffer);
                                Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                                    DataBuffer buffer = exchange.getResponse().bufferFactory()
                                            .wrap(bytes);
                                    return Mono.just(buffer);
                                });
                                ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                        exchange.getRequest()) {
                                    @Override
                                    public Flux<DataBuffer> getBody() {
                                        return cachedFlux;
                                    }
                                };
                                return chain.filter(exchange.mutate().request(mutatedRequest).build());
                            });
                }
            }
            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            return exchange.getResponse().setComplete();
        };
    }
    @Override
    public int getOrder() {
        return 2;
    }
    private Map<String, String> getPathParamValueMap(String path, Map<String, Map<String, String>> paramValueMap) {
        if (paramValueMap == null || paramValueMap.isEmpty()) {
            return null;
        }
        Map<String, String> res = new HashMap<>();
        for (Map.Entry<String, Map<String, String>> paramValueEntry : paramValueMap.entrySet()) {
            String pathPredicate = paramValueEntry.getKey();
            if (antPathMatcher.match(pathPredicate, path)) {
                Map<String, String> paramValue = paramValueEntry.getValue();
                if (paramValue == null) {
                    continue;
                }
                res.putAll(paramValue);
            }
        }
        return res;
    }
    private String extractParam(String jsonStr, String key) {
        try {
            int startIndex = jsonStr.indexOf("\"" + key + "\"");
            if (startIndex != -1) {
                int valueStart = jsonStr.indexOf(':', startIndex);
                int valueEnd = jsonStr.indexOf(',', valueStart);
                if (valueEnd == -1) {
                    valueEnd = jsonStr.indexOf('}', valueStart);
                }
                if (valueStart != -1 && valueEnd != -1) {
                    String valuePart = jsonStr.substring(valueStart + 1, valueEnd).trim();
                    return valuePart.replaceAll("\"", "");
                }
            }
        } catch (Exception e) {
            // 可以記錄日志
            return null;
        }
        return null;
    }
    private boolean pathMatch(String path, Set<String> predicatePaths) {
        if (predicatePaths == null || predicatePaths.isEmpty()) {
            return false;
        }
        return predicatePaths.stream()
                .anyMatch(predicatePath -> antPathMatcher.match(predicatePath, path));
    }
    private boolean paramMatch(Map<String, String> bodyParamMap,
                               Map<String, String> queryParamMap,
                               ServerHttpRequest request,
                               ServerWebExchange exchange
    ) {
        return true;
    }
    private boolean bodyParamMatch(Map<String, String> bodyParamConditions, String bodyStr) {
        if (bodyStr == null) {
            return false;
        }
        for (Map.Entry<String, String> conditionMapEntry : bodyParamConditions.entrySet()) {
            String predicateParam = conditionMapEntry.getKey();
            String predicateValue = conditionMapEntry.getValue();
            String acValue = extractParam(bodyStr, predicateParam);
            if (!predicateValue.equals(acValue)) {
                log.info(" --> bodyParamMatch:::predicateParam:{}, predicateValue:{}, acValue:{},參數(shù)校驗不通過!",
                        predicateParam, predicateValue, acValue);
                return false;
            }
        }
        return true;
    }
    private boolean queryParamMatch(Map<String, String> conditionMap, MultiValueMap<String, String> queryParams) {
        for (Map.Entry<String, String> conditionMapEntry : conditionMap.entrySet()) {
            String predicateParam = conditionMapEntry.getKey();
            String predicateValue = conditionMapEntry.getValue();
            String acValue = queryParams.getFirst(predicateParam);
            if (!predicateValue.equals(acValue)) {
                log.info(" --> queryParamMatch:::predicateParam:{}, predicateValue:{}, acValue:{},參數(shù)校驗不通過!",
                        predicateParam, predicateValue, acValue);
                return false;
            }
        }
        return true;
    }
    private boolean isLimitedIp(String clientIp, Set<String> limitedIps) {
        if (clientIp == null || clientIp.isEmpty()) {
            log.warn(" --> clientIp:{} 為空!", clientIp);
            return true;
        }
        if (limitedIps == null || limitedIps.isEmpty()) {
            log.info(" --> limitedIps:{} 為空!", limitedIps);
            return false;
        }
        for (String limitedIp : limitedIps) {
            if (clientIp.contains(limitedIp)) {
                return true;
            }
        }
        return false;
    }
    // 配置類
    public static class Config {
        private String paths = "/**";
        private String limitedFrom;
        private List<ConditionConfig> conditions = new ArrayList<>();
        private String excludes;
        private Set<String> includesPaths;
        private Set<String> limitedIps = new HashSet<>();
        private Set<String> excludesPaths = new HashSet<>();
        private Map<String, Map<String, String>> bodyParamValueMap = new HashMap<>();
        private Map<String, Map<String, String>> pathParamValueMap = new HashMap<>();
        public void setPaths(String paths) {
            this.paths = paths;
            if (paths != null) {
                this.includesPaths = new HashSet<>(Arrays.asList(paths.split(",")));
            }
        }
        public void setLimitedFrom(String limitedFrom) {
            this.limitedFrom = limitedFrom;
            if (limitedFrom != null) {
                this.limitedIps = new HashSet<>(Arrays.asList(limitedFrom.split(",")));
            }
        }
        public void setConditions(List<ConditionConfig> conditions) {
            this.conditions = conditions;
            if (conditions != null && !conditions.isEmpty()) {
                for (ConditionConfig condition : conditions) {
                    String conditionPaths = condition.getPaths();
                    String bodyParam = condition.getBodyParam();
                    String bodyValue = condition.getBodyValue();
                    String pathParam = condition.getPathParam();
                    String pathValue = condition.getPathValue();
                    if (conditionPaths != null) {
                        if (bodyParam != null && bodyValue != null) {
                            for (String path : conditionPaths.split(",")) {
                                Map<String, String> bodyParamCondition = bodyParamValueMap.get(path);
                                if (bodyParamCondition == null) {
                                    bodyParamCondition = new HashMap<>();
                                }
                                bodyParamCondition.put(bodyParam, bodyValue);
                                bodyParamValueMap.put(path, bodyParamCondition);
                            }
                        }
                        if (pathParam != null && pathValue != null) {
                            for (String path : conditionPaths.split(",")) {
                                Map<String, String> pathParamCondition = pathParamValueMap.get(path);
                                if (pathParamCondition == null) {
                                    pathParamCondition = new HashMap<>();
                                }
                                pathParamCondition.put(pathParam, pathValue);
                                pathParamValueMap.put(path, pathParamCondition);
                            }
                        }
                    }
                }
            }
        }
        public void setExcludes(String excludes) {
            this.excludes = excludes;
            if (excludes != null) {
                this.excludesPaths = new HashSet<>(Arrays.asList(excludes.split(",")));
            }
        }
        public Set<String> getIncludesPaths() {
            return includesPaths;
        }
        public Set<String> getLimitedIps() {
            return limitedIps;
        }
        public Set<String> getExcludesPaths() {
            return excludesPaths;
        }
        public Map<String, Map<String, String>> getBodyParamValueMap() {
            return bodyParamValueMap;
        }
        public Map<String, Map<String, String>> getPathParamValueMap() {
            return pathParamValueMap;
        }
    }
    @Data
    public static class ConditionConfig {
        private String paths;
        private String bodyParam;
        private String bodyValue;
        private String pathParam;
        private String pathValue;
    }
}

借助了工具類IPHelp.java

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@Slf4j
public class IPHelp {
    private static final List<String> IP_HEADERS = Collections.unmodifiableList(Arrays.asList(
            "X-Forwarded-For",
            "x-forwarded-for",
            "xff",
            "x-real-ip",
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_CLIENT_IP",
            "HTTP_X_FORWARDED_FOR"
    ));
    public static String getClientIp(ServerHttpRequest request) {
        String resultIp = null;
        HttpHeaders headers = request.getHeaders();
        for (String head : IP_HEADERS) {
            String ip = headers.getFirst(head);
            log.info(" --> IP_HEADER:{}, IP_VALUE:{}", head, ip);
            if (isValidIp(ip)) {
                resultIp = ip;
                break;
            }
        }
        if (resultIp == null && request.getRemoteAddress() != null) {
            InetSocketAddress remoteAddress = request.getRemoteAddress();
            resultIp = remoteAddress.getAddress().getHostAddress();
            log.info(" --> IP_HEADER: remoteAddress, IP_VALUE:{}", resultIp);
        }
        log.info(" --> getClientIp, IP_VALUE:{}", resultIp);
        return resultIp;
    }
    private static boolean isValidIp(String ip) {
        return ip != null && !ip.trim().isEmpty() && !"unknown".equalsIgnoreCase(ip.trim());
    }
}

RESPECT!

到此這篇關于spring-gateway filters添加自定義過濾器實現(xiàn)(可插拔)的文章就介紹到這了,更多相關spring-gateway filters自定義過濾器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java實現(xiàn)24點小游戲

    Java實現(xiàn)24點小游戲

    這篇文章主要為大家詳細介紹了Java實現(xiàn)24點小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Spring+Vue整合UEditor富文本實現(xiàn)圖片附件上傳的方法

    Spring+Vue整合UEditor富文本實現(xiàn)圖片附件上傳的方法

    這篇文章主要介紹了Spring+Vue整合UEditor富文本實現(xiàn)圖片附件上傳的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-07-07
  • Java使用Lettuce客戶端在Redis在主從復制模式下命令執(zhí)行的操作

    Java使用Lettuce客戶端在Redis在主從復制模式下命令執(zhí)行的操作

    這篇文章主要介紹了Java使用Lettuce客戶端在Redis在主從復制模式下命令執(zhí)行的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Java?Selenide?簡介與用法

    Java?Selenide?簡介與用法

    Selenium?是目前用的最廣泛的Web?UI?自動化測試框架,本文給大家介紹下Java?Selenide使用,感興趣的朋友一起看看吧
    2022-01-01
  • IntelliJ IDEA中Project與Module的概念以及區(qū)別

    IntelliJ IDEA中Project與Module的概念以及區(qū)別

    這篇文章主要給大家介紹了關于IntelliJ IDEA中Project與Module的概念以及區(qū)別的相關資料,文中通過實例介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • java實現(xiàn)interceptor攔截登錄權限

    java實現(xiàn)interceptor攔截登錄權限

    Java里的攔截器是動態(tài)攔截action調用的對象,本文主要介紹了java實現(xiàn)interceptor攔截登錄權限,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • spring啟動后保證創(chuàng)建的對象不被垃圾回收器回收

    spring啟動后保證創(chuàng)建的對象不被垃圾回收器回收

    最近看到一個問題是,spring在啟動后如何保證創(chuàng)建的對象不被垃圾回收器回收?。所以本文結合jvm的垃圾回收機制和spring中的源代碼做出自己的一點猜測。有需要的朋友們可以參考借鑒。
    2016-09-09
  • SpringBoot參數(shù)驗證的幾種方式小結

    SpringBoot參數(shù)驗證的幾種方式小結

    在日常的接口開發(fā)中,為了防止非法參數(shù)對業(yè)務造成影響,經常需要對接口的參數(shù)進行校驗,例如登錄的時候需要校驗用戶名和密碼是否為空,所以本文介紹了SpringBoot參數(shù)驗證的幾種方式,需要的朋友可以參考下
    2024-07-07
  • 本地啟動RocketMQ未映射主機名產生的超時問題最新解決方案

    本地啟動RocketMQ未映射主機名產生的超時問題最新解決方案

    這篇文章主要介紹了本地啟動RocketMQ未映射主機名產生的超時問題,本文給大家分享最新解決方案,感興趣的朋友跟隨小編一起看看吧
    2024-02-02
  • MyBatis源碼分析之日志logging詳解

    MyBatis源碼分析之日志logging詳解

    這篇文章主要給大家介紹了關于MyBatis源碼分析之日志logging的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-03-03

最新評論