Spring Webflux实现OIDC后端登出时logout+jwt不支持的问题求助
解决Spring Webflux/Spring Cloud Gateway中OIDC后端登出的
logout+jwt类型支持问题 问题根源
抛出的BadJOSEException是因为Nimbus的DefaultJOSEObjectTypeVerifier默认仅允许JWT类型的JOSE令牌,而OIDC后端登出请求携带的JWT使用了logout+jwt类型。目前Spring Security Reactive版本尚未像Servlet版本那样内置对该令牌类型的支持,导致验证失败。
解决方案
通过自定义JWT解码器和后端登出认证管理器,扩展对logout+jwt类型的支持,具体步骤如下:
1. 定制支持logout+jwt的NimbusReactiveJwtDecoder
创建自定义解码器,修改JWT处理器的类型验证规则,同时兼容原有JWT类型和新增的logout+jwt类型:
import com.nimbusds.jose.JOSEObjectType; import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier; import com.nimbusds.jwt.proc.DefaultJWTProcessor; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; import java.util.Set; public class LogoutJwtSupportingDecoder { public static ReactiveJwtDecoder create(ClientRegistration clientRegistration) { NimbusReactiveJwtDecoder decoder = NimbusReactiveJwtDecoder .withJwkSetUri(clientRegistration.getProviderDetails().getJwkSetUri()) .build(); // 扩展JOSE类型验证器,允许logout+jwt decoder.setJwtProcessorCustomizer(jwtProcessor -> { if (jwtProcessor instanceof DefaultJWTProcessor<?, ?>) { ((DefaultJWTProcessor<?, ?>) jwtProcessor).setJOSEObjectTypeVerifier( new DefaultJOSEObjectTypeVerifier( Set.of(JOSEObjectType.JWT, new JOSEObjectType("logout+jwt")) ) ); } }); return decoder; } }
2. 自定义OidcBackChannelLogoutReactiveAuthenticationManager
继承默认的后端登出认证管理器,替换其JWT解码器获取逻辑,使用我们定制的解码器:
import org.springframework.security.config.web.server.OidcBackChannelLogoutReactiveAuthenticationManager; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; import reactor.core.publisher.Mono; public class CustomOidcBackChannelLogoutAuthManager extends OidcBackChannelLogoutReactiveAuthenticationManager { private final ReactiveClientRegistrationRepository clientRegistrationRepository; public CustomOidcBackChannelLogoutAuthManager(ReactiveClientRegistrationRepository clientRegistrationRepository) { super(clientRegistrationRepository); this.clientRegistrationRepository = clientRegistrationRepository; } @Override protected Mono<ReactiveJwtDecoder> getJwtDecoder(String issuer) { return this.clientRegistrationRepository.findByRegistrationId(issuer) .map(LogoutJwtSupportingDecoder::create); } }
3. 配置HttpSecurity使用自定义认证管理器
修改原有安全配置,替换默认的后端登出认证管理器:
import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.web.server.SecurityWebFilterChain; @EnableWebFluxSecurity public class SecurityConfig { private final ReactiveClientRegistrationRepository clientRegistrationRepository; public SecurityConfig(ReactiveClientRegistrationRepository clientRegistrationRepository) { this.clientRegistrationRepository = clientRegistrationRepository; } @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { http .oidcLogout(oidcLogout -> oidcLogout .clientRegistrationRepository(clientRegistrationRepository) .backChannel(backChannel -> backChannel .authenticationManager(new CustomOidcBackChannelLogoutAuthManager(clientRegistrationRepository)) ) ); // 补充其他安全配置... return http.build(); } }
说明
该方案通过扩展Nimbus JWT处理器的验证规则,在不破坏原有逻辑的前提下添加对logout+jwt类型的支持,完全兼容OIDC后端登出规范。待Spring Security Reactive版本官方支持该令牌类型后,可直接替换回默认配置。
内容的提问来源于stack exchange,提问作者Cedric
相关产品推荐
相关产品推荐

