我想使用 client_credentials 从反应性资源服务器访问另一个受 oauth2 保护的资源。我使用颁发的令牌访问资源服务器的部分正在工作,但没有使用 webclient 调用其他资源。
使用 UnAuthenticatedServerOAuth2AuthorizedClientRepository 我得到serverWebExchange must be null
,并使用 AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository 我得到principalName must be null
.
Using https://www.baeldung.com/spring-webclient-oauth2 https://www.baeldung.com/spring-webclient-oauth2只要我将客户称为CommandLineRunner
。我在 stackoverflow 上找到的其他建议都不起作用。
我在这里缺少什么?我正在使用 Spring Security 5.2.0 和 Spring Boot 2.2.0。
客户端配置:
@Configuration
public class ClientSecurityConfig {
// UnAuthenticatedServerOAuth2AuthorizedClientRepository version
@Bean
WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
return WebClient.builder()
.filter(oauth)
.build();
}
@Bean
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider(CustomClientConfig clientConfig) {
return ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials(clientCredentialsGrantBuilder ->
clientCredentialsGrantBuilder.accessTokenResponseClient(new CustomClient(clientConfig))) // Used to send extra parameters to adfs server
.build();
}
// AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository version
@Bean
WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
return WebClient.builder()
.filter(oauth)
.build();
}
}
@Bean
ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ServerOAuth2AuthorizedClientRepository authorizedClientRepository, CustomClientConfig clientConfig) {
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials(clientCredentialsGrantBuilder ->
clientCredentialsGrantBuilder.accessTokenResponseClient(new CustomClient(clientConfig))) // Used to send extra parameters to adfs server
.build();
DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultReactiveOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}
资源服务器配置:
@EnableWebFluxSecurity
class ResourceServerConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges ->
exchanges
.pathMatchers("/actuators/**", "/api/v1").permitAll()
.pathMatchers("/api/v1/**").hasAuthority("SCOPE_read")
.anyExchange().authenticated()
)
.formLogin().disable()
.httpBasic().disable()
.oauth2Client(withDefaults())
.oauth2ResourceServer().jwt();
return http.build();
}
@RestController()
@RequestMapping("/api/v1")
static class Ctrl {
final static Logger logger = LoggerFactory.getLogger(Ctrl.class);
final WebClient webClient;
public Ctrl(WebClient webClient) {
this.webClient = webClient;
}
@RequestMapping("protected")
Mono<JsonNode> protected(@RequestParam String data) {
return webClient.post()
.uri("https://other-oauth2-protected-resource")
.attributes(clientRegistrationId("myclient"))
.bodyValue("{\"data\": \"" + data + "\"}")
.retrieve()
.bodyToMono(JsonNode.class);
}
}
}
应用程序.yml:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://adfsserver.com/adfs/services/trust
jwk-set-uri: https://adfsserver.com/adfs/discovery/keys
client:
registration:
myclient:
provider: adfs
client-id: <client-id>
client-secret: <client-secret>
authorization-grant-type: client_credentials
scope: read
provider:
adfs:
token-uri: https://adfsserver.com/adfs/oauth2/token
jwk-set-uri: https://adfsserver.com/adfs/discovery/keys