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

如何编写GatewayFilter将Principal名称作为请求参数传递?

解决方案:Spring Cloud Gateway 动态添加请求参数(从Principal提取clientId)

核心实现逻辑

由于ServerWebExchange不可变、getPrincipal()返回异步类型Mono<Principal>,必须基于响应式编程的链式操作处理:先异步获取Principal,再构建包含新参数的请求实例,最后传递给后续过滤器链。

自定义GatewayFilter代码

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.security.Principal;
import java.util.Collections;

@Component
public class ClientIdRequestParameterFilter implements GatewayFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return exchange.getPrincipal()
                // 异步获取Principal后,构建带clientId参数的新请求
                .map(principal -> {
                    String clientId = principal.getName();
                    // 生成修改后的请求对象
                    ServerHttpRequest modifiedRequest = exchange.getRequest().mutate()
                            .queryParams(params -> params.put("clientId", Collections.singletonList(clientId)))
                            .build();
                    // 生成新的ServerWebExchange(原对象不可变)
                    return exchange.mutate().request(modifiedRequest).build();
                })
                // 处理Principal不存在的场景,直接返回原exchange
                .defaultIfEmpty(exchange)
                // 继续执行后续过滤器链
                .flatMap(modifiedExchange -> chain.filter(modifiedExchange));
    }
}

配置过滤器生效

需要确保该过滤器在认证过滤器之后执行,保证Principal已存在。示例配置类如下:

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GatewayConfig {

    private final ClientIdRequestParameterFilter clientIdFilter;

    public GatewayConfig(ClientIdRequestParameterFilter clientIdFilter) {
        this.clientIdFilter = clientIdFilter;
    }

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("backend_service_route", r -> r.path("/api/**")
                        .filters(f -> f.filter(clientIdFilter))
                        .uri("http://your-backend-service:8080"))
                .build();
    }
}

关键细节说明

  • 异步顺序控制:通过Mono.map()确保先完成Principal的获取和请求修改,再执行后端调用,解决之前逻辑顺序错误的问题。
  • 不可变对象处理:利用mutate()方法创建新的ServerHttpRequest和ServerWebExchange实例,符合Spring WebFlux的设计规范。
  • Lambda变量合规:所有变量均为有效final,满足Java Lambda的语法要求。
  • 异常兜底:defaultIfEmpty(exchange)保证认证失败或Principal不存在时,过滤器链仍能正常流转,避免请求中断。

失败原因复盘

  • 第一种尝试:未使用响应式链式操作,异步任务的执行顺序失控,导致后端调用先于参数修改完成。
  • 第二种尝试:网关自带的AddRequestParameterGatewayFilterFactory仅支持静态参数注入,无法动态从Principal提取数据,必须自定义过滤器实现。

内容的提问来源于stack exchange,提问作者Sergey Zolotarev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 16:04:58