一、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、數據庫等動態配置 |
自定義負載均衡策略 | ReactiveLoadBalancer | Spring 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 Gateway | Netflix 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. 斷言執行原理與順序
斷言是路由匹配的前置條件,執行在過濾器構造 之前
? 原理分析
-
所有
Route
由RouteLocator
管理(比如CachingRouteLocator
)。 -
每個
RouteDefinition
包含一組PredicateDefinition
。 -
加載時這些斷言通過對應的
RoutePredicateFactory
轉換為Predicate<ServerWebExchange>
。 -
網關請求處理器
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 傳遞下游 |
可組合性 | 可與斷言組合使用,形成安全控制鏈 |