java Keycloak与Sping Boot 集成错误:JWS对象的负载不是有效的JSON对象

ryoqjall  于 2023-03-11  发布在  Java
关注(0)|答案(1)|浏览(157)

我们在Sping Boot 3.0.2上运行的项目在为特定客户端集成keycloak 10.0.2(3年前的版本)时遇到了问题。
下面是几个依赖项:
POM:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.2</version>
        <relativePath/>
</parent>

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

application.properties :

spring.security.oauth2.client.registration.keycloak.client-id=client1
spring.security.oauth2.client.registration.keycloak.client-secret=xxxxx-xxxxx
spring.security.oauth2.client.registration.keycloak.client-name=keycloak
spring.security.oauth2.client.registration.keycloak.scope=profile,openid,email
spring.security.oauth2.client.registration.keycloak.redirect-uri=https://localhost:9097/login/oauth2/code/keycloak
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/auth/realms/testrealm2
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/auth/realms/testrealm

Spring安全配置:

@Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf()
        .disable()
        .authorizeHttpRequests()
        .requestMatchers(getStaticResources(coralEnabled).toArray(new String[0]))
        .permitAll()
        .anyRequest()
        .authenticated()
        .and()
        .oauth2Login()
        .successHandler(kwAuthenticationSuccessHandler)
        .failureHandler(kwAuthenticationFailureHandler)
        .failureUrl("/login?error")
        .loginPage("/login")
        .permitAll()
        .and()
        .logout()
        .invalidateHttpSession(true)
        .logoutUrl("/logout")
        .logoutSuccessUrl("/login")
        .addLogoutHandler(
            new HeaderWriterLogoutHandler(
                new ClearSiteDataHeaderWriter(
                    ClearSiteDataHeaderWriter.Directive.CACHE,
                    ClearSiteDataHeaderWriter.Directive.COOKIES,
                    ClearSiteDataHeaderWriter.Directive.STORAGE)));
    return http.build();
  }

@Bean
  WebClient webClient(
      ClientRegistrationRepository clientRegistrationRepository,
      OAuth2AuthorizedClientRepository authorizedClientRepository) {
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 =
        new ServletOAuth2AuthorizedClientExchangeFilterFunction(
            clientRegistrationRepository, authorizedClientRepository);
    oauth2.setDefaultOAuth2AuthorizedClient(true);

    return WebClient.builder().apply(oauth2.oauth2Configuration()).build();
  }

  @Bean
  public AuthorizationRequestRepository<OAuth2AuthorizationRequest>
      authorizationRequestRepository() {
    return new HttpSessionOAuth2AuthorizationRequestRepository();
  }

  @Bean
  public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest>
      accessTokenResponseClient() {
    DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
        new DefaultAuthorizationCodeTokenResponseClient();
    return accessTokenResponseClient;
  }

密钥隐藏版本:10.0.2
Sping Boot Web应用程序是基于UI/Thymeleaf的。
当用户点击UI中的登录按钮时,在nimbus框架中失败:无效的json当尝试到剖析.
错误:

com.nimbusds.jwt.proc.BadJWTException: Payload of JWS object is not a valid JSON object
    at com.nimbusds.jwt.proc.DefaultJWTProcessor.extractJWTClaimsSet(DefaultJWTProcessor.java:262) ~[nimbus-jose-jwt-9.24.4.jar!/:9.24.4]
    at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:352) ~[nimbus-jose-jwt-9.24.4.jar!/:9.24.4]
    at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:303) ~[nimbus-jose-jwt-9.24.4.jar!/:9.24.4]
    at org.springframework.security.oauth2.jwt.NimbusJwtDecoder.createJwt(NimbusJwtDecoder.java:154) ~[spring-security-oauth2-jose-6.0.1.jar!/:6.0.1]
    at org.springframework.security.oauth2.jwt.NimbusJwtDecoder.decode(NimbusJwtDecoder.java:137) ~[spring-security-oauth2-jose-6.0.1.jar!/:6.0.1]
    at org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider.getJwt(OidcAuthorizationCodeAuthenticationProvider.java:245) ~[spring-security-oauth2-client-6.0.1.jar!/:6.0.1]
    at org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider.createOidcToken(OidcAuthorizationCodeAuthenticationProvider.java:236) ~[spring-security-oauth2-client-6.0.1.jar!/:6.0.1]
    at org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider.authenticate(OidcAuthorizationCodeAuthenticationProvider.java:154) ~[spring-security-oauth2-client-6.0.1.jar!/:6.0.1]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182) ~[spring-security-core-6.0.1.jar!/:6.0.1]
    at org.springframework.security.authentication.ObservationAuthenticationManager.lambda$authenticate$1(ObservationAuthenticationManager.java:53) ~[spring-security-core-6.0.1.jar!/:6.0.1]
    at io.micrometer.observation.Observation.observe(Observation.java:559) ~[micrometer-observation-1.10.3.jar!/:1.10.3]
    at org.springframework.security.authentication.ObservationAuthenticationManager.authenticate(ObservationAuthenticationManager.java:52) ~[spring-security-core-6.0.1.jar!/:6.0.1]

其他oauth2集成,如Azure AD、Google,工作正常,但使用keycloak时,注意到解析令牌的一些问题。
经过一些调试后,我们注意到当标记合并时,有两个属性具有相同的名称“sub”,因此json无效。

{
   "exp":1675788223,
   "iat":1675787923,
   "auth_time":1675787563,
   "jti":"c07d2db2-xxxx",
   "iss":"https://login.idm.xxx.com/auth/realms/appid-xxx",
   "aud":"xxxx-dev",
   "sub":"f:5ce9dxxxx:user@user.com",
   "typ":"ID",
   "azp":"xxxx-dev",
   "nonce":"dH4EL-2zxxxx",
   "session_state":"fc0a7xxxx",
   "acr":"0",
   "sub":"user@user.com",
   "groups":[
      "FGM-AuthUser",
      "FGM-admin"
  }

有人知道吗?
将keycloak 10.0.2(spring oauth2配置)与spring Boot 3.0.2集成,并期望身份验证无缝工作,但在nimbus令牌解析期间失败。

k75qkfdt

k75qkfdt1#

这个特定的Keycloak版本已知存在JWT标记(https://issues.redhat.com/browse/KEYCLOAK-14309)中存在重复json密钥的问题。
JSON中的重复键在技术上是可能的(尽管绝对不推荐),因此您只能任由JWT解码器摆布。
不幸的是,NimbusJWT解码器对此非常严格,因为它会拒绝JSON

Invalid JSON: Unexpected duplicate key:sub at position 328.

您的唯一选择是:

  • 升级到没有此错误的新版本keycloak
  • 覆盖Spring Security Oauth2提供的标准JwtDecoder
@Bean
        public JwtDecoder jwtDecoder() {
            // create and return your own jwtDecoder bean here.
            return jwtDecoder;
        }

如果选择定制jwtDecoder路径,则需要在springsecurity上下文中注册定制解码器

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
    http
        .authorizeExchange(exchanges -> exchanges
            .anyExchange().authenticated()
        )
        .oauth2ResourceServer(oauth2 -> oauth2
            .jwt(jwt -> jwt
                .decoder(myCustomDecoder())
            )
        );
    return http.build();
}

相关问题