Spring Cloud Gateway集成OAuth认证路由404问题求助
Spring Cloud Gateway集成OAuth时404及Security冲突问题解决
问题核心分析
- 404错误原因:网关路由规则中,ms_oauth服务的匹配路径是
/oauth2/**,但实际请求路径是/ms_oauth/oauth2/token,路径前缀/ms_oauth导致路由匹配失败,网关找不到对应的路由规则转发请求。 - Security配置冲突:网关是Reactive环境(配置了
spring.main.web-application-type=reactive),但同时启用了@EnableWebSecurity(Servlet环境安全配置)和@EnableWebFluxSecurity(Reactive环境安全配置),两者混用导致CSRF等配置冲突。
解决方案
1. 调整网关路由配置,修复404问题
修改网关的application.properties,调整ms_oauth服务的路由规则,使其匹配带/ms_oauth前缀的路径,并通过过滤器移除前缀后转发到OAuth服务:
spring.cloud.gateway.routes[1].id=ms_oauth spring.cloud.gateway.routes[1].uri=lb://ms_oauth # 匹配带/ms_oauth前缀的oauth2路径 spring.cloud.gateway.routes[1].predicates=Path=/ms_oauth/oauth2/** # 添加RewritePath过滤器,移除/ms_oauth前缀,转发到服务的/oauth2/**路径 spring.cloud.gateway.routes[1].filters[0].name=RewritePath spring.cloud.gateway.routes[1].filters[0].args.regexp=/ms_oauth/(?<segment>.*) spring.cloud.gateway.routes[1].filters[0].args.replacement=/${segment} # 保留原有的RewriteResponseHeader过滤器 spring.cloud.gateway.routes[1].filters[1].name=RewriteResponseHeader spring.cloud.gateway.routes[1].filters[1].args.name=Set-Cookie spring.cloud.gateway.routes[1].filters[1].args.regexp=.* spring.cloud.gateway.routes[1].filters[1].args.replacement=secure-cookie=value; Secure
说明:通过RewritePath过滤器将请求路径/ms_oauth/oauth2/token转换为/oauth2/token,转发到ms_oauth服务,这样就能正确匹配服务端的接口路径。
2. 修复网关Security配置冲突
网关是Reactive环境,需移除Servlet环境的安全配置,只保留Reactive相关配置:
@Configuration @EnableWebFluxSecurity @EnableMethodSecurity public class ResourceServerConfig { @Value("${cors.origins}") private String corsOrigins; @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http .csrf(ServerHttpSecurity.CsrfSpec::disable) .authorizeExchange(exchanges -> exchanges // 允许oauth2相关请求无需认证 .pathMatchers("/ms_oauth/oauth2/**").permitAll() .anyExchange().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())) .cors(cors -> cors.configurationSource(corsConfigurationSource())); return http.build(); } @Bean public JwtAuthenticationConverter jwtAuthenticationConverter() { JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter(); grantedAuthoritiesConverter.setAuthoritiesClaimName("authorities"); grantedAuthoritiesConverter.setAuthorityPrefix(""); JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter(); jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter); return jwtAuthenticationConverter; } @Bean public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) { return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource); } @Bean public JWKSource<SecurityContext> jwkSource() { RSAKey rsaKey = generateRsa(); JWKSet jwkSet = new JWKSet(rsaKey); return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); } private static RSAKey generateRsa() { KeyPair keyPair = generateRsaKey(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); return new RSAKey.Builder(publicKey).privateKey(privateKey).keyID(UUID.randomUUID().toString()).build(); } private static KeyPair generateRsaKey() { KeyPair keyPair; try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); keyPair = keyPairGenerator.generateKeyPair(); } catch (Exception ex) { throw new IllegalStateException(ex); } return keyPair; } @Bean public CorsConfigurationSource corsConfigurationSource() { String[] origins = corsOrigins.split(","); CorsConfiguration corsConfig = new CorsConfiguration(); corsConfig.setAllowedOriginPatterns(Arrays.asList(origins)); corsConfig.setAllowedMethods(Arrays.asList("POST", "GET", "PUT", "DELETE", "PATCH")); corsConfig.setAllowCredentials(true); corsConfig.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfig); return source; } }
说明:
- 移除
@EnableWebSecurity和所有Servlet环境的SecurityFilterChain、FilterRegistrationBean<CorsFilter>,避免与Reactive环境冲突。 - 在
SecurityWebFilterChain中配置路径规则,允许/ms_oauth/oauth2/**路径无需认证(获取token的请求本身不需要认证),其他路径需认证。 - 保留Reactive环境的CORS配置,由
ServerHttpSecurity统一处理。
内容的提问来源于stack exchange,提问作者Jean Fernandine
相关产品推荐
相关产品推荐

