一、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-route
uri: http://localhost:8081
predicates:
- 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 HeaderRoutePredicateFactory
extends 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 MyCustomRoutePredicateFactory
extends 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; }
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
LocalTime now = LocalTime.now();
return now.isAfter(config.getAfter());
};
}
// 可选,用于 YAML 参数绑定顺序
@Override
public List<String> shortcutFieldOrder() {
return List.of("after");
}
}
3️⃣ 使用配置方式
在 application.yml
中:
spring:
cloud:
gateway:
routes:
- id: time-limited-route
uri: http://localhost:8081
predicates:
- 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
}
@Override
public List<String> shortcutFieldOrder() {
return List.of("baseMessage", "preLogger", "postLogger");
}
@Override
public 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-route
uri: http://localhost:8081
predicates:
- 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; }
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
LocalTime now = LocalTime.now();
return now.isAfter(config.getFrom()) && now.isBefore(config.getTo());
};
}
@Override
public 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;
}
@Override
public List<String> shortcutFieldOrder() {
return List.of("headerName", "headerValue");
}
@Override
public 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-route
uri: http://localhost:8081
predicates:
- Path=/secure/**
- TimeRange=08:00,12:00
filters:
- 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;
}
@Override
public List<String> shortcutFieldOrder() {
return List.of("enabled");
}
@Override
public 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-api
uri: http://localhost:8081
predicates:
- 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 传递下游 |
可组合性 | 可与断言组合使用,形成安全控制链 |