You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Cloud Gateway POST请求限流引发鉴权异常问题

问题原因分析

你的POST请求配置了permitAll(),意味着请求不需要经过OAuth2认证,而Spring Cloud Gateway默认的RequestRateLimiter使用PrincipalNameKeyResolver,它会从认证上下文获取用户principal作为限流键值。但未认证的POST请求没有principal,导致KeyResolver返回null,限流过滤器直接拒绝请求,这就是POST请求一开限流就被禁止的核心原因。而GET请求要求authenticated(),请求会经过认证流程生成有效principal,所以限流能正常工作。

解决方案

自定义KeyResolver,兼容已认证和未认证请求:对已认证请求用用户principal作为限流标识,未认证请求用IP作为标识,避免因无principal导致请求被直接拒绝。

1. 实现自定义KeyResolver

创建配置类并定义自定义KeyResolver Bean:

package com.example.gateway.config;

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

@Configuration
public class RateLimitConfig {

    @Bean
    public KeyResolver customKeyResolver() {
        return exchange -> {
            // 优先获取认证用户的principal
            return exchange.getPrincipal()
                    .map(principal -> principal.getName())
                    // 无principal时,使用请求IP作为限流key
                    .switchIfEmpty(Mono.just(
                        exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
                    ));
        };
    }
}

2. 修改网关配置,指定使用自定义KeyResolver

在application.yml的两个限流过滤器配置中,添加key-resolver参数指向自定义Bean:

spring:
  cloud:
    gateway:
      routes:
        - id: productserviceforwarding
          predicates:
            - Path=/products/**
            - Method=GET
          uri: lb://productservice
          filters:
            - TokenRelay=
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1
                redis-rate-limiter.burstCapacity: 1
                key-resolver: "#{@customKeyResolver}" # 新增该行

        - id: productserviceforwarding-post
          predicates:
            - Path=/products/**
            - Method=POST
          uri: lb://productservice
          filters:
            - TokenRelay=
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1
                redis-rate-limiter.burstCapacity: 1
                key-resolver: "#{@customKeyResolver}" # 新增该行

3. 验证效果

重启网关服务后:

  • GET请求:仍以认证用户为限流key,限流规则正常生效,鉴权流程不受影响
  • POST请求:以请求IP为限流key,限流规则正常生效,同时保持permitAll()的鉴权逻辑,不会被直接禁止
简化方案(可选)

如果不需要区分认证/未认证请求,可直接用IP作为统一限流标识,简化KeyResolver实现:

@Bean
public KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(
        exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
    );
}

对应配置中key-resolver改为#{@ipKeyResolver}即可。

内容的提问来源于stack exchange,提问作者White space

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:08:13