Spring Boot 3.4.0 尝试解码 Jwt 时发生错误:无法从当前请求获取 X509Certificate

问题描述 投票:0回答:2

我正在从 Spring Boot 3.2.8 迁移到 3.4.0,从 Spring Cloud 2023.0.3 迁移到 2024.0.0。我的应用程序以非常正常的方式使用 OAuth2 和 Spring Security:

@Slf4j
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@EnableFeignClients
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(JwtDecoder decoder, HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(httpRequests -> httpRequests
                        .requestMatchers("/actuator/**", "/v3/api-docs/**", "/swagger-ui/**").permitAll()
                        .anyRequest().authenticated())
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .csrf(AbstractHttpConfigurer::disable)
                .oauth2ResourceServer(jwtConf -> jwtConf.jwt(jwtConfigurer -> jwtConfigurer.decoder(decoder)));
        return http.build();
    }
}

这是我的

application.yml

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jws-algorithms: ${JWS_ALGORITHMS}
          issuer-uri: ${ISSUER_URI}
          jwk-set-uri: ${JWK_SET_URI}

使用 Spring Boot 3.2.8 一切正常,但在我将版本切换到 3.4.0 后,传入请求开始失败

org.springframework.security.oauth2.server.resource.InvalidBearerTokenException: An error occurred while attempting to decode the Jwt: Unable to obtain X509Certificate from current request.
    at org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider.getJwt(JwtAuthenticationProvider.java:103) ~[spring-security-oauth2-resource-server-6.4.1.jar:6.4.1]
    at org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider.authenticate(JwtAuthenticationProvider.java:88) ~[spring-security-oauth2-resource-server-6.4.1.jar:6.4.1]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182) ~[spring-security-core-6.4.1.jar:6.4.1]
    at org.springframework.security.authentication.ObservationAuthenticationManager.lambda$authenticate$1(ObservationAuthenticationManager.java:54) ~[spring-security-core-6.4.1.jar:6.4.1]
    at io.micrometer.observation.Observation.observe(Observation.java:565) ~[micrometer-observation-1.14.1.jar:1.14.1]
    at org.springframework.security.authentication.ObservationAuthenticationManager.authenticate(ObservationAuthenticationManager.java:53) ~[spring-security-core-6.4.1.jar:6.4.1]
    at org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter.doFilterInternal(BearerTokenAuthenticationFilter.java:137) ~[spring-security-oauth2-resource-server-6.4.1.jar:6.4.1]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.0.jar:6.2.0]

这是我的

jwks.json
的样子:

 "keys" : [ {
    "kty" : "RSA",
    "use" : "sig",
    "alg" : "PS256",
    "kid" : "kid",
    "x5c" : [ "lost-of-chars==" ],
    "x5t#S256" : "lost-of-chars",
    "e" : "AQAB",
    "n" : "lost-of-chars"
  }

我查看了迁移指南,但没有找到任何线索。我的问题是如何解决这个问题。

附注Spring Boot 3.3.0 也会发生同样的情况

spring spring-boot
2个回答
0
投票

目前我用这个声明来解决这个问题

@Bean
JwtDecoder jwtDecoderByJwkKeySetUri(
        ObjectProvider<JwkSetUriJwtDecoderBuilderCustomizer> customizers,
        OAuth2ResourceServerProperties properties
) {
    var jwt = properties.getJwt();
    var builder = NimbusJwtDecoder
            .withJwkSetUri(jwt.getJwkSetUri())
            .jwsAlgorithms(signatureAlgorithms ->
                    jwt.getJwsAlgorithms().stream().map(SignatureAlgorithm::from).forEach(signatureAlgorithms::add)
            );
    customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));

    var issuerUri = jwt.getIssuerUri();
    var validators = List.of(new JwtIssuerValidator(issuerUri), new JwtTimestampValidator());
    var defaultValidator = new DelegatingOAuth2TokenValidator<>(validators);

    var nimbusJwtDecoder = builder.build();
    nimbusJwtDecoder.setJwtValidator(defaultValidator);
    return nimbusJwtDecoder;
}

但是,我怀疑要以正确的方式进行迁移,我需要以某种方式提供证书。


0
投票

这与支持证书绑定(POP)JWT访问令牌验证有关,在Spring Security 6.3.0(对应Spring Boot 3.3.0)中默认添加了X509CertificateThumbprintValidator

OAuth2TokenValidator 负责根据所提供的 X509Certificate 的 SHA-256 指纹验证 Jwt 中的 x5t#S256 声明(如果可用)。

由于

x5t#S256
存在于您的
jwks.json
中,因此将触发此类验证。 但是,请求中不存在客户端证书。可能必须启用相互 TLS。

参考:

© www.soinside.com 2019 - 2024. All rights reserved.