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

Spring Gateway 2023.0.3自定义授权过滤器转发问题求助

解决方案

1. 解决安全问题:拦截外部请求的Authorization头

首先在网关层阻断外部客户端直接携带Bearer token的请求,一旦检测到外部请求带有Authorization头,直接返回403禁止访问,从根源杜绝安全风险。

2. 修复请求转发逻辑并实现内部Token获取

Spring Gateway的ServerHttpRequest是不可变对象,旧代码仅调用mutate().header().build()但未替换原exchange对象,导致修改后的请求头不生效。同时调整逻辑:由网关主动向授权服务器获取内部调用的Bearer token,而非从外部请求中提取。

自定义Gateway过滤器实现

@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 1) // 确保优先级最高,先执行安全校验和Token添加
public class InternalAuthFilter extends AbstractGatewayFilterFactory<InternalAuthFilter.Config> {

    private final WebClient webClient;
    // 授权服务器的Token端点地址
    private static final String TOKEN_URL = "http://spring-auth-server/oauth2/token";
    // 网关在授权服务器注册的客户端凭证
    private static final String CLIENT_ID = "gateway-internal-client";
    private static final String CLIENT_SECRET = "gateway-secret-xxx";

    public InternalAuthFilter(WebClient.Builder webClientBuilder) {
        super(Config.class);
        this.webClient = webClientBuilder.build();
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 1. 校验外部请求是否携带Authorization头,禁止此类请求
            if (exchange.getRequest().getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
                exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                return exchange.getResponse().setComplete();
            }

            // 2. 网关通过客户端凭证模式向授权服务器获取内部调用Token
            return webClient.post()
                    .uri(TOKEN_URL)
                    .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                    .body(BodyInserters.fromFormData("grant_type", "client_credentials")
                            .with("client_id", CLIENT_ID)
                            .with("client_secret", CLIENT_SECRET))
                    .retrieve()
                    .bodyToMono(TokenResponse.class)
                    .flatMap(tokenResponse -> {
                        // 3. 构建新请求并添加Authorization头
                        ServerHttpRequest modifiedRequest = exchange.getRequest().mutate()
                                .header(HttpHeaders.AUTHORIZATION, "Bearer " + tokenResponse.getAccessToken())
                                .build();
                        // 替换exchange并继续执行过滤器链
                        return chain.filter(exchange.mutate().request(modifiedRequest).build());
                    })
                    .onErrorResume(e -> {
                        // Token获取失败时返回500
                        exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                        return exchange.getResponse().setComplete();
                    });
        };
    }

    // 接收授权服务器返回的Token响应
    public static class TokenResponse {
        private String access_token;

        public String getAccessToken() {
            return access_token;
        }

        public void setAccessToken(String access_token) {
            this.access_token = access_token;
        }
    }

    public static class Config {
    }
}

路由配置调整

替换旧过滤器,确保新过滤器生效:

routes:
  - id: auth
    uri: lb://internal
    predicates:
      - Path=/platform/**
    filters:
      - name: CircuitBreaker
      - name: InternalAuthFilter
      - RemoveResponseHeader=Cookie

3. 补充注意事项

  • 需在Spring Authorization Server中注册网关作为客户端,开启client_credentials授权模式,并分配对应权限。
  • 可添加Token缓存逻辑(如使用Redis),避免频繁请求授权服务器。
  • 过滤器优先级设置为最高级,确保安全校验和Token添加逻辑优先执行。

内容的提问来源于stack exchange,提问作者Peter Penzov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 09:34:52