Spring Security OAuth2资源服务器InvalidBearerTokenException问题咨询
你的核心问题很明确:Spring Boot资源服务器配置成了JWT解析模式,但Keycloak返回的是UUID格式的不透明Bearer令牌,不是标准JWT,所以Spring Security尝试解析JWT时直接抛出Malformed token异常。
下面针对你的两个问题逐一说明:
问题1:是否可以告知资源服务器该token是普通Bearer Token而非IdToken?
首先纠正一个概念:你拿到的不是IdToken,是不透明令牌(Opaque Token)——这类令牌是一串无意义的字符串,无法本地解析,必须调用授权服务器(Keycloak)的令牌校验接口(introspect)来验证有效性并获取令牌信息。
所以不是“告知资源服务器不是IdToken”,而是要把资源服务器的配置从JWT模式切换到不透明令牌模式。修改你的SecurityFilterChain配置,把oauth2ResourceServer.jwt()换成oauth2ResourceServer.opaqueToken(),同时配置Keycloak的令牌校验端点和资源服务器自身的客户端凭证(资源服务器需要用这些信息去Keycloak验证令牌)。
修改后的配置示例:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests(authz -> authz.anyRequest().permitAll()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .oauth2ResourceServer(oauth2 -> oauth2 .opaqueToken(opaque -> opaque // 配置Keycloak令牌校验端点与资源服务器客户端信息 .introspectionUri("http://your-keycloak-host/auth/realms/your-realm/protocol/openid-connect/token/introspect") .clientId("your-resource-server-client-id") .clientSecret("your-resource-server-client-secret") ) .authenticationEntryPoint((request, response, exception) -> { System.out.println("Authentication failed"); BearerTokenAuthenticationEntryPoint delegate = new BearerTokenAuthenticationEntryPoint(); delegate.commence(request, response, exception); }) ); return http.build(); }
也可以把配置参数放到application.properties中,避免硬编码:
spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=http://your-keycloak-host/auth/realms/your-realm/protocol/openid-connect/token/introspect spring.security.oauth2.resourceserver.opaquetoken.client-id=your-resource-server-client-id spring.security.oauth2.resourceserver.opaquetoken.client-secret=your-resource-server-client-secret
问题2:将客户端设置为bearer-only能否解决该异常?
不能直接解决,但这是Keycloak端的必要配置。
Keycloak里的bearer-only客户端类型,是用来标记这个客户端只能作为资源服务器接收令牌,不能主动发起授权请求去获取令牌——这是资源服务器客户端的标准配置,但它不会改变Keycloak返回的令牌格式。
你现在的问题是资源服务器解析令牌的方式和令牌格式不匹配,所以哪怕把客户端设为bearer-only,只要资源服务器还是用JWT模式解析,依然会报错。
正确的流程是:
- 在Keycloak中将资源服务器对应的客户端设置为
bearer-only(最佳实践,避免该客户端被误用) - 同时把Spring Security的资源服务器配置改成不透明令牌模式(参考问题1的配置)
这样才能彻底解决Malformed token的异常。
内容的提问来源于stack exchange,提问作者Amir Choubani

