我正在从 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 也会发生同样的情况
目前我用这个声明来解决这个问题
@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;
}
但是,我怀疑要以正确的方式进行迁移,我需要以某种方式提供证书。
这与支持证书绑定(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。
参考: