考虑在配置中定义“org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository”类型的bean

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

我目前在我的项目中使用 Spring OAuth2Client 版本

5.2.4.RELEASE

我已经参考Spring官方文档这里实现了Spring Security。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;

@AllArgsConstructor
@Configuration
@Slf4j
public class WebClientConfig {

    @Bean("AuthProvider")
    WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations,
                authorizedClients);
        oauth.setDefaultOAuth2AuthorizedClient(true);
        oauth.setDefaultClientRegistrationId("AuthProvider");
        return WebClient.builder()
                .filter(oauth)
                .filter(this.logRequest())
                .build();
    }

    
    private ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            log.info("Request: [{}] {}", clientRequest.method(), clientRequest.url());
            log.debug("Payload: {}", clientRequest.body());
            return Mono.just(clientRequest);
        });
    }

application.yaml

   security:
    oauth2:
      client:
        provider:
          AuthProvider:
            token-uri: ${tokenpath<read from environment variable>}
        registration:
          AuthProvider:
            authorization-grant-type: client_credentials
            client-id: ${<read from environment variable>}
            client-secret: ${<read from environment variable>}

应用程序启动时出现以下错误:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method webClient in com.sample.config.WebClientConfig required a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' in your configuration.

如果我遗漏了任何配置,请指出我。另外,我没有从其他 StackOverflow 问题中得到太多帮助。

java spring spring-boot spring-security spring-security-oauth2
7个回答
25
投票

您的 spring-boot 配置非常完美。


问题的根本原因:问题出在application.yaml。要么配置错误,要么没有从环境中选取。

所以,问题不在于OAuth2版本,而在于application.yaml中的配置。

注意:

ReactiveClientRegistrationRepository
bean 仅被创建 当您使用 OAuth2 应用程序所有者详细信息配置客户端时。


我从 start.spring.io 创建了一个新项目,并在其中使用了您的配置。

使用您的配置运行项目后,我遇到了同样的问题。

错误日志:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method webClient in com.example.sampleoauth2.WebClientConfig required a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' that could not be found.

The following candidates were found but could not be injected:
    - Bean method 'clientRegistrationRepository' in 'ReactiveOAuth2ClientConfigurations.ReactiveClientRegistrationRepositoryConfiguration' not loaded because OAuth2 Clients Configured Condition registered clients is not available


Action:

Consider revisiting the entries above or defining a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' in your configuration.

然后,我发现我没有在 application.yml 文件中配置属性。

当您将 spring-boot 应用程序注册为 OAuth 应用程序时,我阅读了 Spring Boot 和 OAuth2.0 文档,了解如何从 github 获取客户端 ID 和客户端秘密(示例)。

一旦我配置了我的应用程序就开始工作了。


我正在使用 spring-boot 2.3.1.RELEASEOAuth2Client 版本 5.3.3

我的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>sampleOauth2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sampleOauth2</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectreactor</groupId>
            <artifactId>reactor-spring</artifactId>
            <version>1.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

我的客户端 github 注册属性为 application.yml:

spring:
  security:
    oauth2:
      client:
        registration:
          github:
            client-id: 22a7100de41c7308d346
            client-secret: 05910ab890be29579e9c183443d92e756c450aaf

您更新的 WebClientConfig @Configuration 类:

package com.example.sampleoauth2;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;

import reactor.core.publisher.Mono;

@Configuration
public class WebClientConfig {

    public static Logger log = LogManager.getLogger();

    @Bean
    public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations,
            ServerOAuth2AuthorizedClientRepository authorizedClients) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations, authorizedClients);
        oauth.setDefaultOAuth2AuthorizedClient(true);
        return WebClient.builder().filter(oauth).filter(this.logRequest()).build();
    }

    private ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            log.info("Request: [{}] {}", clientRequest.method(), clientRequest.url());
            log.debug("Payload: {}", clientRequest.body());
            return Mono.just(clientRequest);
        });
    }
}

成功日志:

   .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.1.RELEASE)

2020-06-26 20:36:08.380  INFO 15956 --- [           main] c.e.s.SampleOauth2Application            : Starting SampleOauth2Application on Anishs-MacBook-Pro.local with PID 15956 (/Users/anish/Downloads/sampleOauth2/target/classes started by anish in /Users/anish/Downloads/sampleOauth2)
2020-06-26 20:36:08.381  INFO 15956 --- [           main] c.e.s.SampleOauth2Application            : No active profile set, falling back to default profiles: default
2020-06-26 20:36:08.935  INFO 15956 --- [           main] ctiveUserDetailsServiceAutoConfiguration : 

Using generated security password: 7c63302f-f913-4aa1-852d-cb8445719acb

2020-06-26 20:36:09.132  INFO 15956 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2020-06-26 20:36:09.138  INFO 15956 --- [           main] c.e.s.SampleOauth2Application            : Started SampleOauth2Application in 0.978 seconds (JVM running for 1.313)

17
投票

我正在使用 Spring Boot 2.3.1.RELEASE 我有同样的问题,我的 pom.xml 在我的 pom.xml 中包含这两个依赖项

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

我删除了以下依赖项,这对我来说很有效:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

并不是说这会解决您的麻烦,但这也可能是您的依赖冲突问题。

另一篇文章让我步入正轨:Reactive OAuth2 with Spring Security 5.3.2 ReactiveClientRegistrationRepository bean 无法找到


7
投票

ReactiveClientRegistrationRepository
带有
Reactive stack (netty)
,不带有
Servlet stack (tomcat)

如果您的

pom.xml
包含
spring-boot-starter-web
,Spring 知道您使用
Servlet stack
,它将加载
ClientRegistrationRepository
而不是
ReactiveClientRegistrationRepository

要创建

WebClient
的bean,您可以使用两种解决方案:

解决方案1:

spring-boot-starter-web
中删除
pom.xml
,以便 Spring 知道您处于
Reactive stack

@Bean
WebClient webClient(
    ReactiveClientRegistrationRepository clientRegistrationRepository,
    ReactiveOAuth2AuthorizedClientService authorizedClientService
) {
    var oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
            new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
                clientRegistrationRepository, authorizedClientService
            )
        );

    oauth.setDefaultClientRegistrationId("AuthProvider");
    return WebClient.builder()
        .filter(oauth)
        .build();
}

解决方案2:

spring-boot-starter-web
保留在
pom.xml

@Bean // with spring-boot-starter-web
WebClient webClient(
    ClientRegistrationRepository clientRegistrationRepository,
    OAuth2AuthorizedClientService authorizedClientService
) {
    var oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
        new AuthorizedClientServiceOAuth2AuthorizedClientManager(
            clientRegistrationRepository, authorizedClientService
        )
    );
    oauth.setDefaultClientRegistrationId("AuthProvider");
    return WebClient.builder()
      .apply(oauth.oauth2Configuration())
      .build();
}

6
投票

我使用了@AnishB 的配置。建议作为答案,但仍然出现错误:

Parameter 0 of method webClient in com.example.sampleoauth2.WebClientConfig required a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' that could not be found.

所以,我必须将这些依赖项与 spring 2.3.1.RELEASE 一起使用

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

这是

WebClientConfig
课程:

@Configuration
public class WebClientConfig {

    private static final Logger log = LoggerFactory.getLogger(WebClientConfig.class);

    @Bean("cr")
    ReactiveClientRegistrationRepository getRegistration(
            @Value("${spring.security.oauth2.client.provider.keycloak.token-uri}") String tokenUri,
            @Value("${spring.security.oauth2.client.registration.keycloak.client-id}") String clientId,
            @Value("${spring.security.oauth2.client.registration.keycloak.client-secret}") String clientSecret
    ) {
        ClientRegistration registration = ClientRegistration
                .withRegistrationId("keycloak")
                .tokenUri(tokenUri)
                .clientId(clientId)
                .clientSecret(clientSecret)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .build();
        return new InMemoryReactiveClientRegistrationRepository(registration);
    }

    @Bean(name = "keycloak")
    WebClient webClient(@Qualifier("cr") ReactiveClientRegistrationRepository clientRegistrations) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
        oauth.setDefaultClientRegistrationId("keycloak");
        return WebClient.builder()
                .filter(oauth)
                .filter(logRequest())
                .build();
    }

    private ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            log.info("Request: [{}] {}", clientRequest.method(), clientRequest.url());
            log.debug("Payload: {}", clientRequest.body());

            return Mono.just(clientRequest);
        });
    }
}

一切工作正常,但对我来说问题是为什么@AnishB 的解决方案。对我不起作用?!


1
投票

就我而言,我在

spring-batch
应用程序 WebClient 中使用
(WebApplicationType.NONE)
。所以没有找到servlet上下文,因此我必须自己配置
ClientRegistrationRepository
OAuth2AuthorizedClientService
OAuth2AuthorizedClientManager


@Configuration
public class WebClientConfiguration {

    @Bean
    public ClientRegistrationRepository clientRegistrationsRepository(
            @Value("${keycloak.registration-id}") String registrationId,
            @Value("${keycloak.token-uri}") String tokenUri,
            @Value("${keycloak.client-id}") String clientId,
            @Value("${keycloak.client-secret}") String clientSecret) {
        ClientRegistration registration = ClientRegistration
                .withRegistrationId(registrationId)
                .tokenUri(tokenUri)
                .clientId(clientId)
                .clientSecret(clientSecret)
                .authorizationGrantType(CLIENT_CREDENTIALS)
                .build();
        return new InMemoryClientRegistrationRepository(registration);
    }

    @Bean
    public OAuth2AuthorizedClientService oAuth2AuthorizedClientService(ClientRegistrationRepository clientRegistrationsRepository) {
        return new InMemoryOAuth2AuthorizedClientService(clientRegistrationsRepository);
    }

    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(
            ClientRegistrationRepository clientRegistrationRepository,
            OAuth2AuthorizedClientService authorizedClientService) {

        OAuth2AuthorizedClientProvider authorizedClientProvider =
                OAuth2AuthorizedClientProviderBuilder.builder()
                        .clientCredentials()
                        .build();

        AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
                new AuthorizedClientServiceOAuth2AuthorizedClientManager(
                        clientRegistrationRepository, authorizedClientService);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

        return authorizedClientManager;
    }

    @Bean
    public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager,
                               @Value("${keycloak.registration-id}") String registrationId) {

        ServletOAuth2AuthorizedClientExchangeFilterFunction auth2Function =
                new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
        auth2Function.setDefaultClientRegistrationId(registrationId);
        return WebClient.builder()
                .apply(auth2Function.oauth2Configuration())
                .build();

    }
}
keycloak:
  registration-id: my-registration
  client-id: my-parameters
  client-secret: g92olxcwBIWYNuSDaEyZrBsYHQPCv04R
  token-uri: http://localhost:8090/auth/realms/my-realm/protocol/openid-connect/token

并添加了这些依赖项:

    implementation "org.springframework.boot:spring-boot-starter-web"
    implementation "org.springframework.boot:spring-boot-starter-webflux"
    implementation "org.springframework.boot:spring-boot-starter-security"
    implementation "org.springframework.boot:spring-boot-starter-oauth2-resource-server"
    implementation "org.springframework.boot:spring-boot-starter-oauth2-client"

0
投票

这是依赖冲突问题。尝试删除网络依赖


0
投票

您只需将此代码添加到您的 application.yml oe application.properties

服务器: 春天: 安全: oauth2: 资源服务器: 智威汤逊: jwk-set-uri: keycloakHost:port/realms/YourRealmenter 代码在这里/协议/openid-connect/certs

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