如何配置Spring Gateway实现OAuth认证代理?
Spring Gateway统一处理OAuth2认证+暴露无验证内网端点实现方案
1. 核心依赖引入
首先在pom.xml中添加Spring Gateway、OAuth2客户端相关依赖:
<dependencies> <!-- Spring Gateway --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- OAuth2 Client --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency> </dependencies>
2. OAuth2客户端与令牌配置
在application.yml中配置外部服务商的OAuth2参数,同时配置用于获取令牌的WebClient支持:
spring: security: oauth2: client: registration: external-service: client-id: YOUR_CLIENT_ID client-secret: YOUR_CLIENT_SECRET authorization-grant-type: client_credentials scope: api_access provider: external-service: token-uri: https://external-service.com/oauth2/token spring: cloud: gateway: default-filters: - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
3. 自定义GlobalFilter实现自动令牌注入
3.1 令牌缓存工具类
实现简单内存缓存避免重复请求令牌,生产环境可替换为分布式缓存:
@Component public class TokenCache { private OAuth2AccessToken cachedToken; private final OAuth2AuthorizedClientManager authorizedClientManager; public TokenCache(OAuth2AuthorizedClientManager authorizedClientManager) { this.authorizedClientManager = authorizedClientManager; } public synchronized OAuth2AccessToken getValidToken() { if (cachedToken == null || cachedToken.isExpired()) { OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("external-service") .principal("gateway-client") .build(); OAuth2AuthorizedClient authorizedClient = authorizedClientManager.authorize(authorizeRequest); cachedToken = authorizedClient.getAccessToken(); } return cachedToken; } }
3.2 全局过滤器实现
编写GlobalFilter,自动为转发到外部服务商的请求注入OAuth2令牌:
@Component public class OAuth2TokenInjectFilter implements GlobalFilter, Ordered { private final TokenCache tokenCache; public OAuth2TokenInjectFilter(TokenCache tokenCache) { this.tokenCache = tokenCache; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 仅对目标代理路由生效,可根据实际路径规则调整 if (exchange.getRequest().getPath().startsWithSegments("/external-api-proxy")) { OAuth2AccessToken token = tokenCache.getValidToken(); ServerHttpRequest modifiedRequest = exchange.getRequest().mutate() .header("Authorization", "Bearer " + token.getTokenValue()) .build(); return chain.filter(exchange.mutate().request(modifiedRequest).build()); } return chain.filter(exchange); } @Override public int getOrder() { // 确保在路由转发前执行令牌注入 return -100; } }
4. 配置无验证端点与路由
4.1 路由规则配置
在application.yml中添加路由,将内网请求转发到外部服务商:
spring: cloud: gateway: routes: - id: external-service-proxy uri: https://external-service.com/api predicates: - Path=/external-api-proxy/** filters: - StripPrefix=1 # 去掉路径前缀/external-api-proxy
4.2 关闭内网端点安全验证
配置SecurityWebFilterChain,允许所有内网请求访问代理端点:
@Configuration public class GatewaySecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http .authorizeExchange(exchanges -> exchanges .anyExchange().permitAll() // 本次不做客户端身份校验 ) .csrf(csrf -> csrf.disable()); // 网关场景下通常关闭CSRF return http.build(); } }
关键说明
- 若外部服务商采用其他授权类型,需调整
authorization-grant-type及对应令牌获取逻辑 - 后续切换自有认证体系时,仅需修改
SecurityWebFilterChain添加客户端认证逻辑,令牌注入模块可复用
内容的提问来源于stack exchange,提问作者DGoiko
相关产品推荐
相关产品推荐

