You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Authorization Server启用OIDC与不透明令牌的配置冲突求助

Spring Authorization Server同时启用OIDC与不透明令牌的解决方案

问题背景

需要在Spring Authorization Server中同时启用OIDC和不透明令牌功能。启用OIDC后,客户端调用/userinfo端点时,使用不透明Bearer令牌会因无法被识别而报错。尝试配置自定义authenticationManagerResolver:

.oauth2ResourceServer(resourceServer ->    
    resourceServer      
        .authenticationManagerResolver(authenticationManagerResolver(resourceServerProperties)));

但出现新错误,原因是启用OIDC时,OAuth2AuthorizationServerConfigurer会自动配置jwt:

OidcConfigurer oidcConfigurer = getConfigurer(OidcConfigurer.class);        
if (oidcConfigurer != null) {            
    if (oidcConfigurer.getConfigurer(OidcUserInfoEndpointConfigurer.class) != null                    
            || oidcConfigurer.getConfigurer(OidcClientRegistrationEndpointConfigurer.class) != null) {                
        httpSecurity                    
            // Accept access tokens for User Info and/or Client Registration                    
            .oauth2ResourceServer(                            
                (oauth2ResourceServer) -> oauth2ResourceServer.jwt(Customizer.withDefaults()));            
    }        
}

错误堆栈如下:

Caused by: java.lang.IllegalStateException: If an authenticationManagerResolver() is configured, then it takes precedence over any jwt() or opaqueToken() configuration.    
at org.springframework.util.Assert.state(Assert.java:79) ~[spring-core-6.2.0.jar:6.2.0]    
at org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer.validateConfiguration(OAuth2ResourceServerConfigurer.java:299) ~[spring-security-config-6.4.1.jar:6.4.1]    
at org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer.init(OAuth2ResourceServerConfigurer.java:260) ~[spring-security-config-6.4.1.jar:6.4.1]    
at org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer.init(OAuth2ResourceServerConfigurer.java:147) ~[spring-security-config-6.4.1.jar:6.4.1]    
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:366) ~[spring-security-config-6.4.1.jar:6.4.1]    
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:328) ~[spring-security-config-6.4.1.jar:6.4.1]    
at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:38) ~[spring-security-config-6.4.1.jar:6.4.1]    
at app.chameleon.authorization.server.config.AuthorizationServerConfig.authorizationServerSecurityFilterChain(AuthorizationServerConfig.java:143) ~[classes/:na]    
at app.chameleon.authorization.server.config.AuthorizationServerConfig$$SpringCGLIB$$0.CGLIB$authorizationServerSecurityFilterChain$9(<generated>) ~[classes/:na]    
at app.chameleon.authorization.server.config.AuthorizationServerConfig$$SpringCGLIB$$FastClass$$1.invoke(<generated>) ~[classes/:na]    
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) ~[spring-core-6.2.0.jar:6.2.0]    
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:348) ~[spring-context-6.2.0.jar:6.2.0]    
at app.chameleon.authorization.server.config.AuthorizationServerConfig$$SpringCGLIB$$0.authorizationServerSecurityFilterChain(<generated>) ~[classes/:na]    
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]    
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]    
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.2.0.jar:6.2.0]    
... 42 common frames omitted

解决方案

1. 自定义AuthenticationManagerResolver,同时支持JWT和不透明令牌

创建一个BearerTokenAuthenticationManagerResolver的实现,根据令牌格式判断使用对应认证管理器:

@Component
public class MultiTokenAuthenticationManagerResolver implements AuthenticationManagerResolver<HttpServletRequest> {

    private final AuthenticationManager jwtAuthenticationManager;
    private final AuthenticationManager opaqueTokenAuthenticationManager;

    public MultiTokenAuthenticationManagerResolver(JwtDecoder jwtDecoder, OAuth2TokenIntrospector introspector) {
        this.jwtAuthenticationManager = new JwtAuthenticationProvider(jwtDecoder)::authenticate;
        this.opaqueTokenAuthenticationManager = new OpaqueTokenAuthenticationProvider(introspector)::authenticate;
    }

    @Override
    public AuthenticationManager resolve(HttpServletRequest request) {
        String token = extractToken(request);
        if (token != null && isJwt(token)) {
            return jwtAuthenticationManager;
        }
        return opaqueTokenAuthenticationManager;
    }

    private String extractToken(HttpServletRequest request) {
        String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            return authorizationHeader.substring(7);
        }
        return null;
    }

    private boolean isJwt(String token) {
        return token.split("\\.").length == 3; // JWT为三段式结构
    }
}

2. 覆盖OIDC自动配置,使用自定义Resolver

在授权服务器的SecurityFilterChain配置中,显式指定使用自定义Resolver,覆盖OIDC自动配置的JWT设置:

@Configuration
public class AuthorizationServerConfig {

    @Autowired
    private MultiTokenAuthenticationManagerResolver authenticationManagerResolver;

    @Bean
    @Order(0)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

        // 启用OIDC功能
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(Customizer.withDefaults());

        // 配置资源服务器使用自定义Resolver,覆盖自动配置的JWT
        http.oauth2ResourceServer(resourceServer ->
                resourceServer.authenticationManagerResolver(authenticationManagerResolver));

        return http.build();
    }

    // 配置JWT解码器
    @Bean
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }

    // 配置不透明令牌校验器
    @Bean
    public OAuth2TokenIntrospector opaqueTokenIntrospector() {
        return new NimbusOpaqueTokenIntrospector(
                "http://localhost:8080/oauth2/introspect", 
                "your-client-id", 
                "your-client-secret"
        );
    }
}

3. 关键说明

  • 错误核心是同时配置authenticationManagerResolver与jwt()/opaqueToken(),Spring Security不允许这种冲突配置,必须二选一。
  • 自定义Resolver需自行实现令牌类型判断逻辑,确保JWT和不透明令牌能被正确路由到对应认证管理器。
  • 需确保OAuth2TokenIntrospector配置正确,用于校验不透明令牌的有效性。

内容的提问来源于stack exchange,提问作者Malvin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 04:23:10