You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot 3.x+Spring Security 6.x OAuth2客户端兼资源服务器(会话Cookie模式)返回403问题排查

Spring Boot 3.x+Spring Security 6.x OAuth2客户端兼资源服务器(会话Cookie模式)返回403问题排查

看起来你遇到的核心问题是两个SecurityFilterChain的匹配逻辑冲突,导致请求还没到达资源服务器的FilterChain就被拒绝了,另外资源服务器的配置也需要适配会话Cookie的认证方式。我来一步步帮你分析和解决:

问题根源分析

  1. FilterChain顺序与路径覆盖问题
    你的clientFilterChain设置了@Order(1)(优先级更高),但没有限定它处理的请求路径范围。这意味着所有请求都会先经过这个FilterChain,而它的authorizeHttpRequests只配置了/api/user/current需要认证,其他路径没有匹配规则——Spring Security默认会对未匹配的请求执行拒绝访问,所以哪怕你在第二个FilterChain里设置permitAll,请求根本到不了那里,直接返回403。

  2. 资源服务器未适配会话认证
    即使解决了FilterChain的路径问题,资源服务器默认只接受请求头中的Bearer Token,但你的客户端是用会话Cookie来请求的,资源服务器无法识别会话中的OAuth2认证信息,也会导致403。

解决方案

步骤1:限定客户端FilterChain的处理范围

修改clientFilterChain,添加requestMatcher让它只处理登录、OAuth2回调和指定的用户接口,其他路径交给资源服务器FilterChain处理:

@Order(1)
@Bean
public SecurityFilterChain clientFilterChain(HttpSecurity httpSecurity) throws Exception {
    return httpSecurity
            // 只处理登录相关路径和/user/current接口
            .requestMatcher(
                new AntPathRequestMatcher("/login/**"),
                new AntPathRequestMatcher("/oauth2/**"),
                new AntPathRequestMatcher("/api/user/current")
            )
            .cors(Customizer.withDefaults())
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(matcherRegistry -> matcherRegistry
                // 登录和OAuth2回调路径允许匿名访问
                .requestMatchers("/login/**", "/oauth2/**").permitAll()
                // /api/user/current需要认证
                .requestMatchers("/api/user/current").authenticated()
            )
            .oauth2Login(loginConfigurer -> loginConfigurer.defaultSuccessUrl(applicationConfiguration.getFrontendRedirectUrl(), true))
            .exceptionHandling(exceptionHandlingConfigurer -> exceptionHandlingConfigurer.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)))
            .logout(logoutConfigurer -> logoutConfigurer.logoutSuccessHandler(logoutSuccessHandler()))
            .build();
}

步骤2:适配资源服务器的会话认证

修改资源服务器FilterChain,允许会话认证,并确保它能识别会话中的OAuth2认证信息:

@Order(2)
@Bean
public SecurityFilterChain resourceServerFilterChain(HttpSecurity httpSecurity) throws Exception {
    return httpSecurity
            .cors(Customizer.withDefaults())
            .csrf(AbstractHttpConfigurer::disable)
            // 允许创建/使用会话,适配Cookie认证
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))
            .authorizeHttpRequests(matcherRegistry -> matcherRegistry.anyRequest().authenticated())
            .oauth2ResourceServer(configurer -> configurer.jwt(Customizer.withDefaults()))
            // 配置会话认证支持,让资源服务器能识别OAuth2登录后的会话信息
            .oauth2Login(Customizer.withDefaults())
            .build();
}

额外检查点

  • 确保你的JWT配置正确:比如Keycloak的JWKS端点(spring.security.oauth2.resourceserver.jwt.jwk-set-uri)配置无误,否则JWT验证失败也会返回403。
  • 检查会话中的认证信息:可以在资源接口中打印SecurityContextHolder.getContext().getAuthentication(),确认是否能获取到OAuth2AuthenticationTokenJwtAuthenticationToken

这样调整后,请求/api/test-data会先经过第二个FilterChain,并且能识别会话中的认证信息,正常处理资源请求。

备注:内容来源于stack exchange,提问作者Robert Strauch

火山引擎 最新活动