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
相关产品推荐
相关产品推荐

