深入剖析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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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…