深入剖析Spring Cloud Gateway,自定義過濾器+斷言組合成攔截器鏈實現Token認證

一、Spring Cloud Gateway網關的整體架構

Spring Cloud Gateway 是 Spring Cloud 官方推出的網關解決方案,旨在替代 Netflix Zuul 1.x。其底層基于 Spring WebFlux + Reactor 模型 構建,具備響應式、異步非阻塞的高性能特點。

1. 整體架構圖

                   +-------------+Client  --->  |  Netty HTTP |  --->  Filter Chain --->  Route Matching+-------------+                            ↓URI Rewrite↓Load Balancer / WebClient↓Target Service

2. 核心組件剖析

1. Netty Server(底層通信)

  • 基于 Spring WebFlux + Netty 實現異步非阻塞的請求接入。

  • Reactor Netty 作為服務器(取代 Tomcat),使用 NIO 支持高并發處理。

  • 請求通過 HttpServer 接入,并封裝為 ServerWebExchange 對象。


2. Route(路由定義)

核心配置單位,決定請求的轉發目標。

路由配置組成:
spring:cloud:gateway:routes:- id: my-routeuri: http://localhost:8081predicates:- Path=/api/**filters:- AddRequestHeader=token, my-token
路由核心類:
  • Route: 單個路由對象,包含 id、uri、predicate、filter 等信息。

  • RouteDefinition: YAML 或 Java DSL 中定義的原始配置。

  • RouteLocator: 路由查找器,默認實現是 CachingRouteLocator,緩存所有 Route


3. Predicate(斷言)

  • 用于匹配請求是否符合某個路由。

  • 每個斷言是一個實現了 GatewayPredicate 的類,底層是 Predicate<ServerWebExchange>

  • 常見內置斷言:Path, Method, Header, Host, Query, RemoteAddr 等。

示例:
exchange -> exchange.getRequest().getURI().getPath().startsWith("/api/")

4. Filter(過濾器)

過濾器鏈結構:
  • Spring Cloud Gateway 采用 責任鏈模式 管理所有過濾器。

  • 分為兩類:

    • 全局過濾器(GlobalFilter):作用于所有請求,如 NettyRoutingFilter, LoadBalancerClientFilter

    • 局部過濾器(GatewayFilter):作用于具體的 Route。

核心類:
  • GatewayFilterChain: 核心接口,調用 filter(ServerWebExchange, GatewayFilterChain) 方法。

  • OrderedGatewayFilter: 帶排序的過濾器包裝類。

  • FilterDefinition: YAML 中的過濾器配置項。

過濾器執行流程圖:
Client --> GlobalFilter1 --> GatewayFilterA --> GatewayFilterB --> GlobalFilter2 --> Backend
內置過濾器示例:
  • AddRequestHeaderGatewayFilterFactory

  • RewritePathGatewayFilterFactory

  • HystrixGatewayFilterFactory(Spring Cloud CircuitBreaker)


5. ServerWebExchange(上下文封裝)

  • 封裝請求 (ServerHttpRequest) 和響應 (ServerHttpResponse)。

  • 貫穿整個生命周期,類似于 Servlet 中的 HttpServletRequest/Response。


6. 轉發請求(NettyRoutingFilter 或 LoadBalancerClientFilter)

  • NettyRoutingFilter: 默認將請求轉發給目標 URI。

  • LoadBalancerClientFilter: 在 URI 為 lb:// 時調用注冊中心負載均衡(集成 Ribbon、Spring Cloud LoadBalancer)。

示例:
// 基于 WebClient 發起轉發請求(WebFlux 非阻塞客戶端)
webClient.method(request.getMethod()).uri(targetUri).headers(httpHeaders -> ...).exchange()

3. 執行流程詳解

請求處理核心流程:

Step 1: Netty 接收請求并生成 ServerWebExchange
Step 2: RouteLocator 匹配路由
Step 3: 斷言 Predicate 判斷是否命中路由
Step 4: 構造過濾器鏈(全局 + 路由)
Step 5: 執行 GatewayFilterChain
Step 6: 最終由 NettyRoutingFilter 或 LoadBalancerClientFilter 發起轉發
Step 7: 響應回傳至客戶端

4. 響應式編程模型(核心基礎)

  • Spring Cloud Gateway 是基于 Reactor 模型構建,響應式、非阻塞、背壓友好。

  • Filter 鏈通過 Mono.defer(() -> filter(...)).then(...) 串聯。

  • 所有邏輯必須是非阻塞,否則會違背設計初衷,導致性能問題。


5. 擴展點

擴展點接口或類說明
自定義斷言RoutePredicateFactory繼承 AbstractRoutePredicateFactory
自定義過濾器GatewayFilterFactory繼承 AbstractGatewayFilterFactory
自定義全局過濾器GlobalFilter直接實現即可
動態路由注冊實現 RouteDefinitionLocator 接口支持 Nacos、數據庫等動態配置
自定義負載均衡策略ReactiveLoadBalancerSpring Cloud LoadBalancer 接口

6.?與 Spring 生態集成

  • 注冊中心集成:通過 Spring Cloud DiscoveryClient + LoadBalancerClientFilter 實現服務名解析。

  • 熔斷限流:結合 Sentinel、Resilience4j、RateLimiter(內置 TokenBucket 限流器)實現。

  • 鏈路追蹤:集成 Sleuth,自動注入 TraceId 進入 header。

  • 認證鑒權:通過局部或全局過濾器在 Filter 中實現 JWT 校驗、權限認證。


7. 性能優勢

特性Spring Cloud Gateway 優勢
異步非阻塞基于 Reactor 模型,比 Zuul 1.x 阻塞式性能更優
支持服務發現與 Spring Cloud 原生集成
靈活可擴展Filter 和 Predicate 都易于擴展
強大配置能力基于 YAML/Java DSL 路由配置能力

8. 底層與 Zuul 對比

對比項Spring Cloud GatewayNetflix Zuul 1.x
編程模型響應式(WebFlux)阻塞(Servlet)
性能高并發、低延遲適中
路由配置方式靈活,支持 Predicate+Filter相對單一
可擴展性非常強一般

二、深入剖析斷言(Predicate)

Spring Cloud Gateway 中的 斷言(Predicate) 是路由匹配的核心機制之一,作用是判斷當前請求是否滿足條件,是否應該命中該路由。斷言具備強大的表達能力,底層通過組合式 Predicate 實現。


1. 斷言(Predicate)概念簡述

  • 本質是 Predicate<ServerWebExchange>,判斷當前請求上下文是否滿足某些規則。

  • 每個路由可以配置多個斷言,必須全部通過,才會命中路由(邏輯與關系)

  • 斷言通過配置文件或 Java DSL 配置,最終轉為 RoutePredicateFactory 執行邏輯。


2. 核心斷言分類(內置 PredicateFactory)

Spring Cloud Gateway 提供了豐富的內置斷言工廠(可擴展)。下面按功能分類剖析它們的參數和底層實現:


1. Path 斷言

功能:基于請求路徑進行匹配。

配置示例:

predicates:- Path=/api/v1/**,/admin/**

參數解析:

  • 接收一個或多個 Ant 風格路徑。

  • 支持通配符 ***

  • 會自動與 Request.Path 比較。

底層類:

  • PathRoutePredicateFactory

  • 實現 apply(Config config) 返回 exchange -> pathMatcher.match(pathPattern, requestPath)


2. Method 斷言

功能:匹配 HTTP 方法。

配置示例:

predicates:- Method=GET,POST

底層類MethodRoutePredicateFactory

參數說明

  • 枚舉形式傳入,如 GET、POST、PUT、DELETE 等。

  • 會轉換為 HttpMethod 比較 exchange.getRequest().getMethod()


3. Header 斷言

功能:匹配請求頭信息。

配置示例:

predicates:- Header=X-Request-Id, ^[0-9]+$

參數說明

  • 第一個參數為請求頭 key,第二個為正則表達式。

  • 正則匹配請求頭的值。

底層類HeaderRoutePredicateFactory


4. Query 斷言

功能:匹配請求 query 參數。

配置示例:

predicates:- Query=version, ^v1$

底層類QueryRoutePredicateFactory

說明

  • key 是 query 參數名。

  • value 是正則表達式,用于匹配參數值。


5. Host 斷言

功能:匹配請求中的 Host 頭部。

配置示例:

predicates:- Host=**.example.org

底層類HostRoutePredicateFactory

說明

  • 支持通配符:*.example.org

  • 實際讀取 Host 頭部進行匹配。


6. RemoteAddr 斷言

功能:基于 IP 地址匹配。

配置示例:

predicates:- RemoteAddr=192.168.1.0/24

底層類RemoteAddrRoutePredicateFactory

說明

  • 支持 CIDR 表達式(子網匹配)。

  • 注意:必須配置 X-Forwarded-For 支持或確保 Netty 獲取真實 IP。


7. After / Before / Between 斷言(基于時間)

predicates:- After=2025-01-01T00:00:00+08:00- Before=2025-12-31T23:59:59+08:00

底層類

  • AfterRoutePredicateFactory

  • BeforeRoutePredicateFactory

  • BetweenRoutePredicateFactory

說明

  • ISO-8601 時間格式,必須包含時區。

  • 匹配當前請求時間是否在設定時間點之前、之后或區間內。


8. Cookie 斷言

predicates:- Cookie=session, ^[a-z0-9]+$

底層類CookieRoutePredicateFactory

說明

  • 斷言某個 Cookie 存在并滿足正則匹配。


3. Predicate 參數結構

YAML 配置風格

- Name=arg1,arg2,arg3

內部通過 Spring Boot 自動綁定為 RoutePredicateFactory.Config 子類。

例如:

public class HeaderRoutePredicateFactoryextends AbstractRoutePredicateFactory<HeaderConfig> {public static class HeaderConfig {private String header;private String regexp;}public Predicate<ServerWebExchange> apply(HeaderConfig config) {return exchange -> {List<String> values = exchange.getRequest().getHeaders().get(config.getHeader());return values != null && values.stream().anyMatch(v -> v.matches(config.getRegexp()));};}
}

4. 自定義 Predicate 實現

1. 實現類繼承方式

繼承:

public class MyCustomRoutePredicateFactoryextends AbstractRoutePredicateFactory<MyConfig> {public Predicate<ServerWebExchange> apply(MyConfig config) {return exchange -> {// 自定義判斷邏輯return true;};}
}

2. 配置方式

predicates:- MyCustom=configValue1,configValue2

3. 自動注冊

只要類名以 RoutePredicateFactory 結尾,Spring 會自動注冊。


5. 組合斷言(多斷言邏輯與)

predicates:- Path=/api/**- Method=GET- Header=X-Auth-Token, .+

執行順序:按配置順序逐一判斷,全部為 true 才匹配成功


6. 調試技巧與陷阱

問題類型原因或建議
路由不匹配斷言順序中某一個未通過
時間斷言失敗時區不一致或格式錯誤
IP 斷言無效網關前有代理,建議配置 ForwardedHeaderFilter
多參數不生效多個 query/header 應用多個斷言條目,而不是一個斷言多個值
正則不匹配注意正則表達式要轉義,避免 YAML 被錯誤解析

三、深入剖析過濾器(Filter)

1. 執行總流程概覽

Spring Cloud Gateway 請求生命周期:

1. 客戶端發起請求
2. Netty 接收請求并封裝為 ServerWebExchange
3. RouteLocator 查找所有 Route(含斷言 Predicate)
4. Predicate 執行(逐個判斷,全部通過才命中 Route)
5. 構建 GatewayFilterChain(全局過濾器 + 路由過濾器)
6. 依序執行過濾器鏈(前置邏輯 → 發起請求轉發 → 后置邏輯)
7. 收到目標服務響應,經過過濾器返回響應

2. 斷言執行原理與順序

斷言是路由匹配的前置條件,執行在過濾器構造 之前

? 原理分析

  1. 所有 RouteRouteLocator 管理(比如 CachingRouteLocator)。

  2. 每個 RouteDefinition 包含一組 PredicateDefinition

  3. 加載時這些斷言通過對應的 RoutePredicateFactory 轉換為 Predicate<ServerWebExchange>

  4. 網關請求處理器 RoutePredicateHandlerMapping 會將所有路由依次嘗試匹配這些 Predicate。

// RoutePredicateHandlerMapping 中的匹配邏輯(簡化)
for (Route route : this.routeLocator.getRoutes()) {if (route.getPredicate().test(exchange)) {return route;}
}

? 順序與邏輯

  • 按路由在配置文件中定義的順序查找。

  • 每個路由內部的多個斷言為 AND 邏輯,所有斷言返回 true 才命中。

  • 匹配成功后立即終止查找,執行對應的過濾器鏈。


3. 過濾器執行原理與順序

過濾器構成了 真正的處理鏈,所有請求響應的處理均由其決定。

? 執行模型

  • 過濾器鏈使用 責任鏈模式 構建,封裝為 GatewayFilterChain

  • 本質是通過遞歸調用 filter(exchange, chain) 來串聯執行。

public Mono<Void> filter(ServerWebExchange exchange) {return filter0(0, exchange);
}private Mono<Void> filter0(int index, ServerWebExchange exchange) {if (index == filters.size()) {return Mono.empty(); // 結束鏈}GatewayFilter filter = filters.get(index);return filter.filter(exchange, e -> filter0(index + 1, exchange));
}

4. 過濾器類型與排序機制

兩類過濾器:

類型接口應用范圍
全局過濾器GlobalFilter所有請求
局部過濾器GatewayFilterFactory匹配路由

排序機制(統一使用 Spring 的 Ordered 接口)

  • 過濾器最終封裝為 OrderedGatewayFilter,具有 getOrder() 值。

  • 數字越小優先級越高,先執行

  • 默認值參考:

    • NettyRoutingFilter: Ordered.LOWEST_PRECEDENCE(最后執行,實際轉發)

    • LoadBalancerClientFilter: 10150

    • RemoveRequestHeaderFilter: 1


5. 過濾器執行階段劃分

每個過濾器可以分為兩個階段:

階段方法位置功能說明
前置處理filter(exchange, chain) 方法前部邏輯修改請求、日志、校驗、安全等
后置處理chain.filter(exchange).then(...)記錄響應日志、處理響應內容等

示例:

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("前置邏輯");return chain.filter(exchange).then(Mono.fromRunnable(() -> {log.info("后置邏輯");}));
}

6. 斷言 vs 過濾器的執行順序對比

執行組件執行階段是否參與實際請求處理是否可修改請求是否參與響應處理
Predicate路由匹配前?(只判斷,不處理)?(間接地)?
Filter路由匹配后???

? 總結順序:

[1] 路由列表加載
[2] Predicate 按序執行判斷是否命中(所有斷言 AND 關系)
[3] 命中后構造 GatewayFilterChain(全局 + 路由)
[4] 按 Ordered 排序執行 filter(責任鏈遞歸調用)

7.?實戰示意圖

+-------------------+
| Client Request    |
+-------------------+↓
[RoutePredicateHandlerMapping]↓
[Predicate1] → true
[Predicate2] → true↓ 命中路由↓ 構造 Ordered GatewayFilterChain↓
→ GlobalFilter1 (order=1)
→ GatewayFilterA (order=5)
→ GatewayFilterB (order=10)
→ LoadBalancerClientFilter (order=10150)
→ NettyRoutingFilter (order=LOWEST)↓
[發起 HTTP 請求]↓
[響應處理 → 倒序執行后置邏輯]

8.?調試建議

目的調試方式
查看是否匹配路由打印路由斷言執行日志或開啟 debug 日志
查看過濾器執行順序自定義過濾器實現 Ordered,打日志確認鏈執行順序
排查過濾器不生效檢查是否被早期過濾器 short-circuit 或未加到 route 中

9. 補充:Spring Gateway 源碼關鍵類

功能類名
路由匹配RoutePredicateHandlerMapping
斷言執行AbstractRoutePredicateFactory 子類
路由構建RouteLocator, CachingRouteLocator
全局過濾器GlobalFilter 接口
路由過濾器GatewayFilterFactory, GatewayFilter
過濾器執行鏈GatewayFilterChain, OrderedGatewayFilter

四、自定義斷言和過濾器的實現

1. 自定義斷言(Route Predicate)

1?? 斷言作用

斷言用于匹配路由規則,只有當斷言通過時,路由才會被選中。


2?? 實現步驟

Step 1:創建斷言工廠類

必須繼承:

AbstractRoutePredicateFactory<YourConfig>
示例:只有在早上9點后才允許路由生效
@Component
public class TimeAfterRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeAfterRoutePredicateFactory.Config> {public TimeAfterRoutePredicateFactory() {super(Config.class);}public static class Config {private LocalTime after;public LocalTime getAfter() { return after; }public void setAfter(LocalTime after) { this.after = after; }}@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return exchange -> {LocalTime now = LocalTime.now();return now.isAfter(config.getAfter());};}// 可選,用于 YAML 參數綁定順序@Overridepublic List<String> shortcutFieldOrder() {return List.of("after");}
}

3?? 使用配置方式

application.yml 中:

spring:cloud:gateway:routes:- id: time-limited-routeuri: http://localhost:8081predicates:- Path=/time/**- TimeAfter=09:00:00

?? 注意:

  • TimeAfter 對應的是工廠類名去掉 RoutePredicateFactory 后的部分。

  • 參數順序來自 shortcutFieldOrder() 方法。


2. 自定義過濾器(GatewayFilter)

1?? 過濾器作用

用于增強請求處理邏輯:鑒權、日志、限流、重寫路徑、頭部處理等。


2?? 實現步驟

Step 1:創建過濾器工廠類

繼承:

AbstractGatewayFilterFactory<YourConfig>
示例:記錄請求日志
@Component
public class LogGatewayFilterFactory extends AbstractGatewayFilterFactory<LogGatewayFilterFactory.Config> {public LogGatewayFilterFactory() {super(Config.class);}public static class Config {private String baseMessage;private boolean preLogger;private boolean postLogger;// Getter/Setter}@Overridepublic List<String> shortcutFieldOrder() {return List.of("baseMessage", "preLogger", "postLogger");}@Overridepublic GatewayFilter apply(Config config) {return (exchange, chain) -> {if (config.preLogger) {System.out.println("[PRE] " + config.baseMessage + " 請求路徑: " + exchange.getRequest().getURI());}return chain.filter(exchange).then(Mono.fromRunnable(() -> {if (config.postLogger) {System.out.println("[POST] 響應碼: " + exchange.getResponse().getStatusCode());}}));};}
}

3?? 使用配置方式

application.yml 中:

spring:cloud:gateway:routes:- id: log-filter-routeuri: http://localhost:8081predicates:- Path=/log/**filters:- Log=訪問日志,true,true

解釋:

  • Log 對應類名 LogGatewayFilterFactory

  • 配置參數順序由 shortcutFieldOrder 決定


3. 執行順序說明

  • 路由 → Predicate 判斷是否命中 → 構建 GatewayFilterChain

  • GatewayFilterChain 按 Ordered 順序執行

  • 自定義過濾器可以通過實現 OrderedGatewayFilter 指定優先級

示例(設置順序):

return new OrderedGatewayFilter((exchange, chain) -> {// filter logic
}, 10); // 優先級為 10

4. 調試技巧

目的方法
確認斷言是否生效在斷言中加日志打印 / 使用 Spring Boot DevTools
確認過濾器執行順序打印日志 + 設置 Ordered 顯式順序
參數綁定失敗檢查 shortcutFieldOrder() 參數名一致性
多個過濾器調試用不同前綴標識并組合多個過濾器調試執行鏈

5. 小結對比

維度斷言(Predicate)過濾器(Filter)
用途路由選擇條件請求/響應增強邏輯
執行時機在請求處理鏈構建之前在請求處理鏈中間
擴展方式繼承 AbstractRoutePredicateFactory繼承 AbstractGatewayFilterFactory
配置方式predicates: - CustomName=val1,...filters: - CustomName=val1,...
控制順序不支持順序控制(都是 AND)支持順序,需使用 OrderedGatewayFilter
示例用途限定時間、Header、Method、IP 白名單等鑒權、加解密、日志記錄、限流、路徑重寫、CORS 等等

五、自定義過濾器+斷言組合成攔截器鏈

1.?核心理念:攔截器鏈的行為建模

在 Gateway 中:

攔截器功能對應概念特點
匹配請求斷言(Predicate)用于路由匹配條件,匹配失敗就跳過
攔截處理過濾器(GatewayFilter)支持鏈式處理、前置、后置邏輯

它們組合使用時形成如下攔截流程:

客戶端請求↓
全局過濾器(GlobalFilter)↓
斷言1 → 不滿足則跳過當前Route
斷言2 → 不滿足則跳過當前Route
...
滿足所有斷言(命中路由)↓
GatewayFilter1 → GatewayFilter2 → ...↓
目標服務(URI)↓
響應時倒序執行后置邏輯

2. 自定義斷言 + 自定義過濾器組合示例

目標:只允許在上午時間段訪問 /secure/** 接口,并打印日志、添加請求頭。


1?? 自定義斷言:TimeRangeRoutePredicateFactory

@Component
public class TimeRangeRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeRangeRoutePredicateFactory.Config> {public TimeRangeRoutePredicateFactory() {super(Config.class);}public static class Config {private LocalTime from;private LocalTime to;public LocalTime getFrom() { return from; }public void setFrom(LocalTime from) { this.from = from; }public LocalTime getTo() { return to; }public void setTo(LocalTime to) { this.to = to; }}@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return exchange -> {LocalTime now = LocalTime.now();return now.isAfter(config.getFrom()) && now.isBefore(config.getTo());};}@Overridepublic List<String> shortcutFieldOrder() {return List.of("from", "to");}
}

2?? 自定義過濾器:AddHeaderAndLogGatewayFilterFactory

@Component
public class AddHeaderAndLogGatewayFilterFactory extends AbstractGatewayFilterFactory<AddHeaderAndLogGatewayFilterFactory.Config> {public AddHeaderAndLogGatewayFilterFactory() {super(Config.class);}public static class Config {private String headerName;private String headerValue;}@Overridepublic List<String> shortcutFieldOrder() {return List.of("headerName", "headerValue");}@Overridepublic GatewayFilter apply(Config config) {return (exchange, chain) -> {System.out.println("[前置] 添加Header: " + config.headerName);exchange.getRequest().mutate().header(config.headerName, config.headerValue).build();return chain.filter(exchange).then(Mono.fromRunnable(() -> System.out.println("[后置] 響應完成")));};}
}

3?? 配置使用(application.yml

spring:cloud:gateway:routes:- id: secure-routeuri: http://localhost:8081predicates:- Path=/secure/**- TimeRange=08:00,12:00filters:- AddHeaderAndLog=X-Request-Source,Gateway

3. 執行流程圖(攔截器鏈建模)

請求 /secure/hello↓
斷言 Path=/secure/** ?
斷言 TimeRange=08:00-12:00 ?↓
執行過濾器鏈:- AddHeaderAndLog 前置日志 & 添加請求頭- 請求轉發- AddHeaderAndLog 后置日志↓
目標服務響應

4. 高階擴展建議

功能需求處理方式
多條件斷言組合自定義組合 Predicate 實現(或多個 predicate 同時配置)
動態參數過濾支持 SpEL 或讀取配置中心值
攔截 + 鑒權 + 路由打標將斷言 + Filter + Header 添加等組合構成完整網關管控鏈
多個過濾器組合順序控制new OrderedGatewayFilter(filter, order) 明確順序

5. 小結

模塊功能說明組合效果
斷言判斷請求是否應被處理(路由條件)攔截器鏈頭部條件篩選
過濾器對匹配的請求執行前后處理邏輯攔截器鏈的核心執行流程
組合條件滿足 → 執行鏈式請求增強類似 Spring MVC 的攔截器鏈

六、實現基于 Token 的認證邏輯

在 Spring Cloud Gateway 中實現基于 Token 的認證邏輯,核心思路是:
使用**自定義過濾器(GatewayFilter)**對請求進行攔截,提取 Token → 驗簽/解析 → 決定是否放行

場景目標

網關層實現對所有請求的 Token 驗證,校驗失敗直接返回 401,無需進入下游服務。


1. 技術選型

  • ? 使用 JWT(JSON Web Token) 作為 Token 格式

  • ? 自定義 GatewayFilter 攔截請求,校驗 JWT 合法性

  • ? 校驗通過 → 繼續路由

  • ? 校驗失敗 → 返回統一錯誤響應


2. Token 示例(JWT)

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiJ1c2VyMSIsImlhdCI6MTY5MjAwMDAwMCwiZXhwIjoxNjkyMDAzNjAwfQ.
Nf8cnRku7k7lDghnK8kluhXbZ1bIsvPrKjD7v4-HqDU

3. 自定義 Token 過濾器實現

🔧 1. JWT 工具類(可使用 jjwt

public class JwtUtil {private static final String SECRET_KEY = "my-secret";public static Claims parseToken(String token) throws JwtException {return Jwts.parser().setSigningKey(SECRET_KEY.getBytes(StandardCharsets.UTF_8)).parseClaimsJws(token).getBody();}
}

🔐 2. 自定義過濾器 TokenAuthGatewayFilterFactory

@Component
public class TokenAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenAuthGatewayFilterFactory.Config> {public TokenAuthGatewayFilterFactory() {super(Config.class);}public static class Config {private boolean enabled;}@Overridepublic List<String> shortcutFieldOrder() {return List.of("enabled");}@Overridepublic GatewayFilter apply(Config config) {return (exchange, chain) -> {if (!config.enabled) {return chain.filter(exchange);}ServerHttpRequest request = exchange.getRequest();String token = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);if (token == null || !token.startsWith("Bearer ")) {return unauthorized(exchange, "Token missing or malformed");}try {Claims claims = JwtUtil.parseToken(token.replace("Bearer ", ""));// 可將用戶信息寫入 Header 或請求屬性中request = exchange.getRequest().mutate().header("X-User-Id", claims.getSubject()).build();return chain.filter(exchange.mutate().request(request).build());} catch (JwtException e) {return unauthorized(exchange, "Token invalid: " + e.getMessage());}};}private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);byte[] bytes = ("{\"error\": \"" + message + "\"}").getBytes(StandardCharsets.UTF_8);return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(bytes)));}
}

4. 配置使用示例 application.yml

spring:cloud:gateway:routes:- id: secure-apiuri: http://localhost:8081predicates:- Path=/secure/**filters:- TokenAuth=true

5.?認證流程圖

請求 /secure/hello→ 進入 Gateway→ 匹配斷言 Path=/secure/**→ 執行過濾器 TokenAuth→ 從 Header 中提取 Bearer Token→ 校驗簽名 & 有效期→ 失敗返回 401→ 成功添加用戶信息繼續路由→ 路由到后端服務

6. Token 認證增強建議(可選)

需求實現建議
白名單路徑免認證配置 if 條件跳過部分 Path
支持 Redis Token 存儲Token 可存 Redis + 校驗時檢查有效性(如登出或禁用)
支持權限角色檢查claims 中附帶 roles → 寫入 Header → 后端根據角色判定權限
動態開關鑒權application.yml 配置 flag 或使用 Nacos 動態刷新
統一異常處理 & 返回結構配合 GlobalFilter 實現通用異常響應包裝邏輯

7. 測試示例

curl -H "Authorization: Bearer <your-token>" http://localhost:8080/secure/hello

8. 依賴庫參考

pom.xml 中添加:

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

9. 小結

項目實現組件
鑒權入口自定義 GatewayFilter
Token 格式JWT,簽名加密后傳遞
鑒權失敗響應自定義 401 輸出
用戶透傳將用戶信息加入 header 傳遞下游
可組合性可與斷言組合使用,形成安全控制鏈

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87933.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87933.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87933.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

VMware Workstation Pro下Centos 7.9 安裝

背景系統安裝方案1、VMware安裝? ? 1.1、下載? ? 1.2、安裝 2、Centos 7.9 安裝? ? 2.1 、Centos7.9 iso 下載? ? 2.2、使用VMware 安裝? ? 2.2.1、VMware配置虛擬機? ? 2.2.2、Linux安裝 結語 背景 本文所在專欄的所有文章基于Centos7.9系統來演示&#xff0c;系…

我做個一個APP叫【圖影工具箱】:一站式解決視頻提取音頻和加水印的鴻蒙神器

在數字內容創作和日常使用手機的過程中&#xff0c;提取視頻音頻、處理圖片和視頻水印是一大需求。許多人在尋找合適的軟件時&#xff0c;往往試遍各種工具卻仍無法滿足需求。所以&#xff0c;我做了一款應用 —— 圖影工具箱&#xff0c;一站式解決這些令人頭疼的問題。 圖影…

【StarRocks系列】查詢語句執行全流程

目錄 StarRocks 查詢數據流程詳解 1. 提交查詢語句 2. FE 解析與優化 3. 選擇 BE 節點與數據路由 4. BE 數據讀取與計算 5. 結果返回 關鍵優化點總結 示例流程 流程圖 StarRocks 查詢數據流程詳解 StarRocks 采用分布式 MPP 架構&#xff0c;查詢流程涉及 FE&#xff…

HarmonyOS 5的分布式通信矩陣是如何工作的?

HarmonyOS 5 的分布式通信矩陣通過多層級技術協同實現跨設備高效協同&#xff0c;其核心工作機制如下&#xff1a; 一、核心架構&#xff1a;分布式軟總線 3.0? ?動態拓撲感知? 設備自動發現并構建最優傳輸路徑&#xff08;如手機與智慧屏優先采用 Wi-Fi P2P 直連&#xf…

自定義Django rest_framework中response的示例

在實際項目開發中&#xff0c;原有框架的response可能并不能完全滿足我們的需求。比如我們需要定義一些更加詳細的RESULT_CODE來說明情況。那么我們就可以基于原有的response進行自定義。 下面是一個自定義Django rest_framework中response的示例 # -*- coding:utf-8 -*- imp…

如何開發HarmonyOS 5的分布式通信功能?

以下是基于HarmonyOS 5開發分布式通信功能的完整技術指南&#xff0c;涵蓋核心流程與關鍵代碼實現&#xff1a; 一、開發前置配置 權限聲明? 在module.json5中添加分布式權限&#xff1a; {"module": {"requestPermissions": [{"name": &quo…

Linux --靜態庫和動態庫的制作和原理

本章重點&#xff1a; 動靜態庫的制作&#xff0c;使用和查找 可執行程序ELF格式 可執行程序的加載過程 虛擬地址空間和動態庫加載的過程 動靜態庫的制作&#xff0c;使用和查找 1.在了解庫的制作之前&#xff0c;我們首先需要知道什么是庫。庫是寫好的現有的&#xff0c;成…

50天50個小項目 (Vue3 + Tailwindcss V4) ? | IncrementingCounter(遞增計數器)

&#x1f4c5; 我們繼續 50 個小項目挑戰&#xff01;—— IncrementingCounter組件 倉庫地址&#xff1a;https://github.com/SunACong/50-vue-projects 項目預覽地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API 和 <script setup&g…

簡約求職簡歷競聘工作求職PPT模版共享

簡歷競聘&#xff0c;自我介紹&#xff0c;個人簡歷&#xff0c;工作求職PPT模版&#xff0c;崗位競聘求職簡歷PPT模版&#xff0c;低調綠自我介紹PPT模版&#xff0c;簡約求職簡歷PPT模版&#xff0c;個人介紹PPT模版&#xff0c;我的簡歷PPT模版&#xff0c;個人求職簡介PPT模…

Java大廠面試攻略:Spring Boot與微服務架構深度剖析

問題一&#xff1a;Spring Boot 的自動配置原理是什么&#xff1f; 簡潔面試回答&#xff1a; Spring Boot 的自動配置基于條件化配置&#xff0c;通過 Conditional 注解實現&#xff0c;根據項目中依賴和環境自動裝配 Bean。 詳細解析&#xff1a; Spring Boot 自動配置的核…

Windows核心端口攻防全解析:135、139、445端口的技術內幕與安全實踐

Windows核心端口攻防全解析&#xff1a;135、139、445端口的技術內幕與安全實踐 引言&#xff1a;Windows網絡通信的命脈 在Windows網絡生態系統中&#xff0c;135、139和445端口猶如網絡通信的"大動脈"&#xff0c;承載著關鍵的系統服務和網絡功能。這些端口不僅是…

從生活場景學透 JavaScript 原型與原型鏈

一、構造函數&#xff1a;以 “人” 為例的對象工廠 1. 生活場景下的構造函數定義 我們以 “人” 為場景創建構造函數&#xff0c;每個人都有姓名、年齡等個性化屬性&#xff0c;也有人類共有的特征&#xff1a; // 人類構造函數 function Person(name, age) {this.name na…

學c++ cpp 可以投遞哪些崗位

此次描述知識針對應屆生來說哈&#xff0c;如果是社招&#xff0c;更多是對于你目前從事的方向&#xff0c;技術棧進行招聘就好了。 此次編寫是按照boss上崗位篩選的方式進行編寫的&#xff0c;其實投簡歷一般也是用boss&#xff0c;后面也會出一篇文章給大家介紹一般找工作都用…

【Docker基礎】Docker鏡像管理:docker rmi、prune詳解

目錄 引言 1 Docker鏡像管理概述 1.1 為什么需要鏡像清理&#xff1f; 1.2 鏡像生命周期管理 2 docker rmi命令詳解 2.1 基本語法 2.2 常用選項 2.3 刪除單個鏡像 2.4 刪除多個鏡像 2.5 強制刪除鏡像 2.6 刪除所有鏡像 3 docker rmi工作原理 3.1 鏡像刪除流程 3.…

57-Oracle SQL Profile(23ai)實操

在上一期中說到了SQL Tuning Advisor其中一個影響對象就是SQL Profile&#xff0c;同樣在管理和應用開發中,SQL性能優化是個任重道遠的工作&#xff0c;低效的SQL語句讓應用響應緩慢,用戶整體體驗下降,拖垮搞蹦整個系統都有可能。Oracle數據庫提供了多種組合工具&#xff0c;有…

man的使用

man的使用 文章目錄 man的使用基本用法&#xff1a;常見 man 命令操作&#xff1a;man 命令的章節&#xff1a;示例&#xff1a; man 是 Linux 和 macOS 系統中的命令&#xff0c;用于查看命令和程序的手冊頁&#xff08;manual pages&#xff09;。手冊頁包含了關于命令、函…

【藍牙】手機連接Linux系統藍牙配對,Linux Qt5分享PDF到手機

要實現手機連接 A40i Linux 系統并通過藍牙接收 PDF 文件&#xff0c;可以按照以下步驟操作&#xff1a; 1. 配置 Linux 藍牙功能 確保開發板上的藍牙模塊已正確驅動并支持藍牙協議棧。 安裝藍牙工具&#xff1a; bash sudo apt install bluetooth bluez bluez-tools 啟動藍…

1432. 改變一個整數能得到的最大差值

1432. 改變一個整數能得到的最大差值 題目鏈接&#xff1a;1432. 改變一個整數能得到的最大差值 代碼如下&#xff1a; class Solution { public:int maxDiff(int num) {string s to_string(num);function<int(char, char)> replace_stoi [&](char old_char, cha…

解密 Spring MVC:從 Tomcat 到 Controller 的一次完整請求之旅

今天&#xff0c;想和你聊一個我們每天都在打交道&#xff0c;但可能不曾深入思考的話題&#xff1a;當一個 HTTP 請求從瀏覽器發出&#xff0c;到最終被我們的 Spring Controller 處理&#xff0c;它到底經歷了一場怎樣的旅程&#xff1f; 理解這個流程&#xff0c;不僅僅是為…

在 Java 中操作 Map時,高效遍歷和安全刪除數據

在 Java 中操作 Map 時&#xff0c;高效遍歷和安全刪除數據可以通過以下方式實現&#xff1a; 一、遍歷 Map 的 4 種高效方式 1. 傳統迭代器&#xff08;Iterator&#xff09; Map<String, Integer> map new HashMap<>(); map.put("key1", 5); map.pu…