对于最新的稳定版本,请使用 Spring Security 7.0.4spring-doc.cadn.net.cn

OAuth 2.0 变更

验证typ带有JwtTypeValidator

NimbusJwtDecoder 在 Spring Security 7 中将把 typ 头验证移至 JwtTypeValidator,而不是依赖 Nimbus 进行验证。 这使其与 NimbusJwtDecoder 验证声明的方式保持一致,不再依赖 Nimbus 来进行验证。spring-doc.cadn.net.cn

如果在jwtProcessorCustomizer方法中更改Nimbus的标准类型验证,那么你应该将这部分代码移动到JwtTypeValidator或你自己的OAuth2TokenValidator实现中。spring-doc.cadn.net.cn

要检查您是否为此次更改做好了准备,请将默认的JwtTypeValidator添加到您的验证器列表中,因为从7版本开始它将被包含在内:spring-doc.cadn.net.cn

@Bean
JwtDecoder jwtDecoder() {
	NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
        .validateTypes(false) (1)
        // ... your remaining configuration
        .build();
	jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
		new JwtIssuerValidator(location), JwtTypeValidator.jwt())); (2)
	return jwtDecoder;
}
@Bean
fun jwtDecoder(): JwtDecoder {
    val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
        .validateTypes(false) (1)
        // ... your remaining configuration
        .build()
    jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
        JwtIssuerValidator(location), JwtTypeValidator.jwt())) (2)
    return jwtDecoder
}
1 - 关闭 Nimbus 验证 typ(从 7 版本开始这将是默认关闭的)
2 - 添加默认的typ验证器(此验证器将在7版本中默认包含)

注意,默认值验证的是typ的值要么是JWT,要么不存在,这与Nimbus默认设置相同。 这也符合RFC 7515的规定,该规定指出typ是可选的。spring-doc.cadn.net.cn

我正在使用DefaultJOSEObjectTypeVerifier

如果您的配置如下所示:spring-doc.cadn.net.cn

@Bean
JwtDecoder jwtDecoder() {
	NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
        .jwtProcessorCustomizer((c) -> c
            .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>("JOSE"))
        )
        .build();
	return jwtDecoder;
}
@Bean
fun jwtDecoder(): JwtDecoder {
    val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
        .jwtProcessorCustomizer {
            it.setJWSTypeVerifier(DefaultJOSEObjectTypeVerifier("JOSE"))
        }
        .build()
    return jwtDecoder
}

然后更改为此:spring-doc.cadn.net.cn

@Bean
JwtDecoder jwtDecoder() {
	NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
        .validateTypes(false)
        .build();
	jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
		new JwtIssuerValidator(location), new JwtTypeValidator("JOSE")));
	return jwtDecoder;
}
@Bean
fun jwtDecoder(): JwtDecoder {
    val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
        .validateTypes(false)
        .build()
	jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators(
		JwtIssuerValidator(location), JwtTypeValidator("JOSE")))
    return jwtDecoder
}

要表示typ头是可选的,请使用#setAllowEmpty(true)(这相当于在null中将DefaultJOSEObjectTypeVerifier包含在允许的类型列表中)。spring-doc.cadn.net.cn

我想选择退出

如果您想继续按当前方式操作,那么步骤相似,只是顺序相反:spring-doc.cadn.net.cn

@Bean
JwtDecoder jwtDecoder() {
	NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
        .validateTypes(true) (1)
        .jwtProcessorCustomizer((c) -> c
            .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>("JOSE"))
        )
        .build();
	jwtDecoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>(
		new JwtTimestampValidator(), new JwtIssuerValidator(location))); (2)
	return jwtDecoder;
}
@Bean
fun jwtDecoder(): JwtDecoder {
    val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location)
        .validateTypes(true) (1)
        .jwtProcessorCustomizer {
            it.setJWSTypeVerifier(DefaultJOSEObjectTypeVerifier("JOSE"))
        }
        .build()
	jwtDecoder.setJwtValidator(DelegatingOAuth2TokenValidator(
        JwtTimestampValidator(), JwtIssuerValidator(location))) (2)
    return jwtDecoder
}
1 - 请保留Nimbus类型的验证
2 - 指定您需要的验证器列表,不包括JwtTypeValidator

对于更多指导,请参阅参考中的JwtDecoder 验证器部分。spring-doc.cadn.net.cn

不透明Tokens凭证将为您进行编码

为了更接近实现 Introspection RFC,Spring Security 的不透明Tokens支持将在创建授权头之前对客户端ID和密钥进行编码。 这意味着您不再需要自己对客户端ID和密钥进行编码。spring-doc.cadn.net.cn

如果您的客户端ID或密钥包含URL不安全的字符,您可以采取以下措施进行准备:spring-doc.cadn.net.cn

替换使用introspectionClientCredentials

由于 Spring Security 现在可以为您执行编码,请将 使用 introspectionClientCredentials 替换为发布以下 @Beanspring-doc.cadn.net.cn

@Bean
OpaqueTokenIntrospector introspector() {
	return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
            .clientId(unencodedClientId).clientSecret(unencodedClientSecret).build();
}
@Bean
fun introspector(): OpaqueTokenIntrospector {
    return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
            .clientId(unencodedClientId).clientSecret(unencodedClientSecret).build()
}

以上将在7.0版本中作为默认设置。spring-doc.cadn.net.cn

如果此设置给您带来麻烦或您当前无法应用,请改用RestOperations构造函数:spring-doc.cadn.net.cn

@Bean
OpaqueTokenIntrospector introspector() {
	RestTemplate rest = new RestTemplate();
	rest.addInterceptor(new BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret));
	return new SpringOpaqueTokenIntrospector(introspectionUri, rest);
}
@Bean
fun introspector(): OpaqueTokenIntrospector {
	val rest = RestTemplate()
	rest.addInterceptor(BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret))
	return SpringOpaqueTokenIntrospector(introspectionUri, rest)
}