OAuth 2.0 更改

驗證typ标题与JwtTypeValidator

NimbusJwtDecoder在 Spring Security 7 中,将移动typheader validation 设置为JwtTypeValidator而不是依赖 Nimbus。这使其符合NimbusJwtDecoder验证声明,而不是依赖 Nimbus 来验证它们。spring-doc.cadn.net.cn

如果您要更改 Nimbus 的默认类型验证,则在jwtProcessorCustomizer方法,那么你应该将其移动到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 保持一致,该 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
}

要指示typheader 是可选的,使用#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发布以下内容@Bean:spring-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

如果此设置给您带来麻烦或您暂时无法应用它,您可以使用RestOperationsconstructor 代替: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)
}