当前位置: 首页 > 知识库问答 >
问题:

Spring boot 2 OAuth2“HTTP Content-Type头必须是application/json”

顾嘉纳
2023-03-14
Your login attempt was not successful, try again.

Reason: [invalid_token_response] An error occurred parsing the Access Token response: The HTTP Content-Type header must be application/json; charset=UTF-8
Authentication request failed: org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_token_response] An error occurred parsing the Access Token response: The HTTP Content-Type header must be application/json; charset=UTF-8
org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_token_response] An error occurred parsing the Access Token response: The HTTP Content-Type header must be application/json; charset=UTF-8
   at org.springframework.security.oauth2.client.endpoint.NimbusAuthorizationCodeTokenResponseClient.getTokenResponse(NimbusAuthorizationCodeTokenResponseClient.java:105) ~[spring-security-oauth2-client-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.oauth2.client.endpoint.NimbusAuthorizationCodeTokenResponseClient.getTokenResponse(NimbusAuthorizationCodeTokenResponseClient.java:67) ~[spring-security-oauth2-client-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider.authenticate(OAuth2LoginAuthenticationProvider.java:113) ~[spring-security-oauth2-client-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) ~[spring-security-core-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.attemptAuthentication(OAuth2LoginAuthenticationFilter.java:129) ~[spring-security-oauth2-client-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:109) [spring-security-oauth2-client-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) [spring-security-web-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.0.2.RELEASE.jar:5.0.2.RELEASE]
   at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_144]
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_144]
   at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.23.jar:8.5.23]
   at java.lang.Thread.run(Thread.java:748) [?:1.8.0_144]
Caused by: com.nimbusds.oauth2.sdk.ParseException: The HTTP Content-Type header must be application/json; charset=UTF-8
   at com.nimbusds.oauth2.sdk.util.ContentTypeUtils.ensureContentType(ContentTypeUtils.java:52) ~[oauth2-oidc-sdk-5.38.jar:5.38]
   at com.nimbusds.oauth2.sdk.http.HTTPMessage.ensureContentType(HTTPMessage.java:133) ~[oauth2-oidc-sdk-5.38.jar:5.38]
   at com.nimbusds.oauth2.sdk.http.HTTPResponse.ensureContentType(HTTPResponse.java:1) ~[oauth2-oidc-sdk-5.38.jar:5.38]
   at com.nimbusds.oauth2.sdk.http.HTTPResponse.getContentAsJSONObject(HTTPResponse.java:369) ~[oauth2-oidc-sdk-5.38.jar:5.38]
   at com.nimbusds.oauth2.sdk.AccessTokenResponse.parse(AccessTokenResponse.java:235) ~[oauth2-oidc-sdk-5.38.jar:5.38]
   at com.nimbusds.oauth2.sdk.TokenResponse.parse(TokenResponse.java:74) ~[oauth2-oidc-sdk-5.38.jar:5.38]
   at org.springframework.security.oauth2.client.endpoint.NimbusAuthorizationCodeTokenResponseClient.getTokenResponse(NimbusAuthorizationCodeTokenResponseClient.java:101) ~[spring-security-oauth2-client-5.0.0.RELEASE.jar:5.0.0.RELEASE]
   ... 60 more    
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("xe").secret("password")
            .authorizedGrantTypes("authorization_code", "refresh_token", "password").scopes("user")
            .autoApprove(true);
    }

    @Override
    public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager);
    }

    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }
}


@Configuration
@EnableWebSecurity
@Order(-20)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/login").permitAll().anyRequest().authenticated()
            .and().formLogin().permitAll();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser(User.withDefaultPasswordEncoder().username("tom").password("111").roles("USER"));
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
spring.security.oauth2.client.registration.xe.client-id=xe
spring.security.oauth2.client.registration.xe.client-secret=password
spring.security.oauth2.client.registration.xe.client-name=xe
spring.security.oauth2.client.registration.xe.provider=x-auth
spring.security.oauth2.client.registration.xe.scope=user
spring.security.oauth2.client.registration.xe.redirect-uri-template={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.xe.client-authentication-method=post
spring.security.oauth2.client.registration.xe.authorization-grant-type=authorization_code

spring.security.oauth2.client.provider.x-auth.authorization-uri=http://localhost:9090/auth/oauth/authorize
spring.security.oauth2.client.provider.x-auth.token-uri=http://localhost:9090/auth/oauth/token
spring.security.oauth2.client.provider.x-auth.user-info-uri=http://localhost:9090/auth/user
spring.security.oauth2.client.provider.x-auth.jwk-set-uri=http://localhost:9090/token_keys
spring.security.oauth2.client.provider.x-auth.user-name-attribute=username
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.M7</version>
    <relativePath />
</parent>
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>

并且在客户端pom中

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.M7</version>
</parent>
...
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-client</artifactId>
    <version>5.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-jose</artifactId>
    <version>5.0.0.RELEASE</version>
</dependency>

共有1个答案

钱黎明
2023-03-14

NimbusAuthorizationCodeTokenResponseClient在内部使用Nimbus OAuth2.0 SDK类发送令牌请求(TokenRequest)并解析令牌响应(TokenResponse)。

标记响应是通过tokenresponse.parse()解析的,当它检查以确保content-type标头在响应中可用并将其设置为application/json时,就会发生错误。这是spring-security-oauth的一个bug,我已经在这里记录了这个问题。

在解决这个问题之前,spring-security-oauth的一个可能的解决方案是使用@controlleradvise截获来自tokenendpoint的响应,并将content-type=application/json标头添加到响应中,如下所示:

@ControllerAdvice(assignableTypes = TokenEndpoint.class)
public class TokenEndpointResponseAdvice<T> implements ResponseBodyAdvice<T> {

    @Override
    public boolean supports(MethodParameter returnType,
                        Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Nullable
    @Override
    public T beforeBodyWrite(@Nullable T body,
                         MethodParameter returnType,
                         MediaType selectedContentType,
                         Class<? extends HttpMessageConverter<?>> selectedConverterType,
                         ServerHttpRequest request,
                         ServerHttpResponse response) {

        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        return body;
    }
}
 类似资料:
  • 我正在创建一个SpringBoot2OAuth2客户机/服务器应用程序。授权服务器成功登录并重定向到客户端,但客户端收到重定向时(http://localhost:8080/login/oauth2/code/xe?code=ACK4Ae 堆栈跟踪 服务器代码 SpringBoot2客户端配置 在服务器pom中 在客户端pom中

  • JSONException:JSONObject文本必须以字符6处的{开头。

  • 我有一个来自REST服务的JSON: 我正在使用java-json.jar来解析这个JSON,这是我试图传递到JSON字符串上方的简单片段: 但我得到了下面的例外: 首先,我假设这是因为JSON中的和字符,并尝试替换如下: 但即便如此,我也遇到了同样的例外。谁能指导我知道我做错了什么吗?

  • 我用RSA实现了数据加密/解密。如果我只是在本地加密/解密,它可以工作,但是如果我发送加密的数据,我会得到BadPaddingException:数据必须从零开始。 为了通过网络发送数据,我需要在客户端将数据从字节数组改为字符串(我以报头的形式发送),然后在服务器端检索数据并将其改回字节数组。 这里是我的本地加密/解密代码(我使用私钥加密,使用公钥解密): DecryptedString和mess

  • 问题内容: 我曾经有ElasticSearch 5.2,并且刚升级到6.0。 我正在尝试按照此处的指南创建索引模板,但出现错误 我的查询是 问题答案: 要解决此问题,请添加curl选项 这个错误是由于 严格的内容类型检查 在ElasticSearch 6.0中引入,在解释这个岗位 从Elasticsearch 6.0开始,所有包含主体的REST请求也必须提供该主体的正确内容类型。

  • 问题内容: 我已经将Elasticsearch(5.5版)集成到Gitlab中并尝试使用它。这是我从外部Windows客户端发送的命令: 但这不起作用。在客户端上,我得到以下错误: {“错误”:“不支持Content-Type标头[应用程序/ x-www-form-urlencoded]”,“状态”:406} curl:(6)无法解析主机:text curl:(3)[globbing ]第1列 c