实战二:网关统一鉴权 + 限流落地
网关是流量总闸,最适合做两件横切的事:统一鉴权(所有请求先验身份)与集中限流(按用户/IP 控配额)。本章在 Spring Cloud Gateway 上落地最小可运行方案:GlobalFilter 校验令牌,Redis 限流器按用户限流。
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- RequestRateLimiter 依赖响应式 Redis 客户端 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
统一鉴权:GlobalFilter
GlobalFilter 对每个请求生效,先于转发执行。示例校验 Authorization 头(生产通常验 JWT 签名或调认证服务,本例封装在 AuthService,密钥放配置中心):
@Component
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private final AuthService authService;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (!authService.valid(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().writeWith(Mono.just(
exchange.getResponse().bufferFactory()
.wrap("{\"code\":401,\"msg\":\"未登录或令牌失效\"}".getBytes())));
}
return chain.filter(exchange); // 白名单路径(登录/健康检查)在 authService 放行
}
@Override
public int getOrder() { return -100; } // 高优先级,先于路由
}
要点:下游默认信任网关转发的身份头,需内网隔离防伪造;过滤器里不要做远程查库等重活,否则它自己成为瓶颈。
集中限流:RequestRateLimiter
多实例共享配额必须用 Redis 令牌桶,三要素:过滤器参数、KeyResolver(限流维度)、Redis。
@Configuration
public class RateLimitConfig {
@Bean
public KeyResolver userKeyResolver() {
return exchange -> { // 按用户 ID 限流,取不到退回 IP
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
return Mono.just(userId != null ? userId
: exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
};
}
}
spring:
cloud:
gateway:
routes:
- id: order-route
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
key-resolver: "#{@userKeyResolver}"
redis-rate-limiter.replenish-rate: 10 # 每秒补 10 个令牌
redis-rate-limiter.burst-capacity: 20 # 突发容量 20
redis-rate-limiter.requested-tokens: 1
超配额默认返回 429。replenish-rate 定稳定速率,burst-capacity 允许短时突发(两者相等即退化为匀速);Redis 不可用时请求会被拒绝,需保证 Redis 高可用或配置降级。
运行与验证
- 启动 Redis、Nacos、order-service 与网关。
- 不带令牌请求
/api/order/**→ 401。 - 带合法令牌请求 → 正常转发到 order-service。
- 快速连续请求超过 burst-capacity → 429;观察 Redis 中按用户生成的限流 key。
- 启动第二实例,验证配额集群共享(同一用户两边合计受限)。
常见问题
- 过滤器顺序:鉴权过滤器 getOrder 必须小于其他过滤器,否则请求先被转发。
- KeyResolver 空 Key:全部请求汇聚到一个桶互相挤占,务必有兜底维度。
- 阈值设定:replenish-rate 依据压测数据(见压测章节),配太小会误杀正常流量。
- 无状态:鉴权不落本地会话、限流状态在 Redis,多实例才能随意扩。
小结
网关统一鉴权解决“每个服务重复验身份”,集中限流解决“单实例限流管不住总量”。本例骨架(GlobalFilter + Redis 令牌桶 + KeyResolver)可直接扩展:令牌换 JWT 验签、维度换接口+用户组合、叠加灰度头路由,即构成生产网关的核心能力集。