Spring Cloud Gateway未自动重定向至授权服务器问题排查
我正在将Spring Cloud Gateway应用配置为OAuth2客户端,已在安全配置类中设置白名单路径。预期未授权用户访问受保护路径时,系统会自动重定向至Google登录授权页,但实际访问时仅返回401错误,并未触发重定向。
代码示例
应用主类
@SpringBootApplication public class SsoApplication { public static void main(String[] args) { SpringApplication.run(SsoApplication.class, args); } @RestController public class WelcomeController { @GetMapping public String openPath() { return "this is open path"; } @GetMapping("/secured") public String securedPath() { return "Accessing secured path"; } } }
安全配置类
@Configuration @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) { return http .authorizeExchange(exchange -> exchange .pathMatchers("/", "/*.css", "/*.js", "/favicon.ico").permitAll() .pathMatchers("/actuator/**").permitAll() .anyExchange().authenticated() ) .exceptionHandling(exceptionHandling -> exceptionHandling .authenticationEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED))) .oauth2Login(Customizer.withDefaults()) .build(); } }
application.yml
spring: security: oauth2: client: registration: google: client-id: #client_id# client-secret: #secret# redirect-uri: "{baseUrl}/login/oauth2/code/google" server: port: 9999
build.gradle
plugins { id 'java' id 'org.springframework.boot' version '3.2.1' id 'io.spring.dependency-management' version '1.1.4' } group = 'com.example' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '17' } repositories { mavenCentral() } ext { set('springCloudVersion', "2023.0.0") } dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'org.springframework.cloud:spring-cloud-starter-gateway' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.projectreactor:reactor-test' } dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } }
尝试过的方案
在
SecurityWebFilterChainbean上添加@Order(Ordered.HIGHEST_PRECEDENCE)访问受保护路径返回HTTP ERROR 401,未重定向至登录页
移除
SecurityConfig类上的@Configuration注解解决了重定向问题,但所有白名单路径变为受限制状态
移除
@EnableWebFluxSecurity并保留@Configuration访问受保护路径返回HTTP ERROR 401,未重定向至登录页
在application.yml中添加
redirection-uri: "{baseUrl}/login/oauth2/code/google"访问受保护路径返回HTTP ERROR 401,未重定向至登录页
注:在方案1、3中,手动访问/oauth2/authorization/google可正常重定向至登录页;此前在spring-boot-starter-web应用中实现相同逻辑正常,实际是因为web应用未配置authenticationEntryPoint。
问题分析与解决方案
核心原因
你手动配置了HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)作为认证入口点,这会强制系统在未授权时直接返回401响应,覆盖了OAuth2登录默认的重定向逻辑。在WebFlux环境下,OAuth2登录默认使用RedirectServerAuthenticationEntryPoint,负责引导未授权用户跳转到第三方授权页面。
解决方案1:移除自定义认证入口点
直接删除exceptionHandling中自定义的authenticationEntryPoint配置,让Spring使用默认的OAuth2重定向逻辑:
@Configuration @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) { return http .authorizeExchange(exchange -> exchange .pathMatchers("/", "/*.css", "/*.js", "/favicon.ico").permitAll() .pathMatchers("/actuator/**").permitAll() .anyExchange().authenticated() ) .oauth2Login(Customizer.withDefaults()) .build(); } }
解决方案2:自定义场景适配(如需保留401逻辑)
如果需要针对某些场景返回401,其他场景触发OAuth2重定向,可以自定义认证入口点逻辑:
@Configuration @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) { return http .authorizeExchange(exchange -> exchange .pathMatchers("/", "/*.css", "/*.js", "/favicon.ico").permitAll() .pathMatchers("/actuator/**").permitAll() .anyExchange().authenticated() ) .exceptionHandling(exceptionHandling -> exceptionHandling .authenticationEntryPoint((exchange, ex) -> { // 判断是否为需要OAuth2认证的场景 ServerWebExchangeMatcher matcher = ServerWebExchangeMatchers.pathMatchers("/secured/**"); matcher.matches(exchange).subscribe(matchResult -> { if (matchResult.isMatch()) { // 触发Google OAuth2登录重定向 RedirectServerAuthenticationEntryPoint entryPoint = new RedirectServerAuthenticationEntryPoint("/oauth2/authorization/google"); entryPoint.commence(exchange, ex).subscribe(); } else { // 其他场景返回401 new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED).commence(exchange, ex).subscribe(); } }); }) ) .oauth2Login(Customizer.withDefaults()) .build(); } }
关于移除@Configuration的疑问
移除@Configuration后,你的自定义安全配置不会被Spring加载,此时系统会启用默认的WebFlux安全配置:默认配置会触发OAuth2重定向,但默认授权规则是所有路径都需要认证,所以你的白名单路径也会被保护,这就是为什么重定向正常但白名单失效的原因。
内容的提问来源于stack exchange,提问作者Erfan Ahmed

