在 Spring MVC 中初始化 OAuth WebClient Bean

Posted

技术标签:

【中文标题】在 Spring MVC 中初始化 OAuth WebClient Bean【英文标题】:Initialising OAuth WebClient Bean in Spring MVC 【发布时间】:2020-11-30 01:21:20 【问题描述】:

我有一个 WebApp JSP 项目作为 WAR 部署在 Weblogic 12 上。

我的 gradle 构建包括 mvc 和 webflux:

implementation 'org.springframework.boot:spring-boot-starter-web:2.3.2.RELEASE'
implementation ("org.springframework.boot:spring-boot-starter-security:2.3.2.RELEASE")
implementation ("org.springframework.boot:spring-boot-starter-oauth2-client:2.3.2.RELEASE")
implementation ("org.springframework.boot:spring-boot-starter-webflux:2.3.2.RELEASE")

我正在尝试将 OAuth2 配置为使用来自我的客户端 JSP 应用程序的 client_credentials 流。

我需要 @Controller 类来使用 WebClient 并将访问令牌传播到资源服务器。

我创建 WebClient 的 Bean 如下所示。

@Bean
public ReactiveClientRegistrationRepository getRegistration() 
    ClientRegistration registration = ClientRegistration
            .withRegistrationId("ei-gateway")
            .tokenUri("https://xxxxx.xxxxxxx.net/auth/oauth/v2/token")
            .clientId("xxx-xxxx-43e9-a407-xxxxx")
            .clientSecret("xxxxxx-3d21-4905-b6e5-xxxxxxxxxx")
            .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
            .build();
    return new InMemoryReactiveClientRegistrationRepository(registration);



@Bean
public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations, ServerOAuth2AuthorizedClientRepository authorizedClients) 

    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
    oauth.setDefaultOAuth2AuthorizedClient(true);
    return WebClient.builder()
            .filter(oauth)
            .defaultHeader("accept", "application/json")
            .defaultHeader("content-type", "application/json")
            .defaultHeader("environment", environment)
            .filter(logRequest())
            .filter(logResponse())
            .build();

但是在编译过程中出现以下错误:

Could not autowire. There is more than one bean of 'ReactiveClientRegistrationRepository' type.
Beans:
clientRegistrationRepository   (ReactiveOAuth2ClientConfigurations.class) 
getRegistration   (WebSecurityConfiguration.java) 

但是,当我取消注释 getRegistration Bean 方法并通过 web.xml 配置 oauth 客户端注册时,部署应用程序时出现此错误:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: :org.springframework.beans.factory.NoSuchBeanDefinitionException:No qualifying bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: 

我从 ReactiveOAuth2ClientAutoConfiguration 源代码中看到,当设置了 ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition 时,Reactive OAuth2 Auto Configuration 没有运行。

@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(ReactiveSecurityAutoConfiguration.class)
@EnableConfigurationProperties(OAuth2ClientProperties.class)
@Conditional(ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition.class)
@ConditionalOnClass( Flux.class, EnableWebFluxSecurity.class, ClientRegistration.class )
@Import( ReactiveOAuth2ClientConfigurations.ReactiveClientRegistrationRepositoryConfiguration.class,
        ReactiveOAuth2ClientConfigurations.ReactiveOAuth2ClientConfiguration.class )
public class ReactiveOAuth2ClientAutoConfiguration 

任何人都可以提出行动方案吗?是否可以手动配置 ReactiveOAuth2ClientConfiguration?

谢谢

【问题讨论】:

【参考方案1】:

根据我的理解,ReactiveClientRegistrationRepository 不可用,因为您没有使用反应式堆栈,以下是如何设置 WebClient 以在 Servlet 环境中使用。

设置应用程序属性,以便 Spring 为您自动连接 ClientRegistrationRepositoryOAuth2AuthorizedClientRepository

spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://xxxxx.xxxxxxx.net/auth/oauth/v2/token
spring.security.oauth2.client.registration.ei-gateway.client-id=xxx-xxxx-43e9-a407-xxxxx
spring.security.oauth2.client.registration.ei-gateway.client-xxxxxx-3d21-4905-b6e5-xxxxxxxxxx
spring.security.oauth2.client.registration.ei-gateway.provider=my-oauth-provider
spring.security.oauth2.client.registration.ei-gateway.scope=read,write
spring.security.oauth2.client.registration.ei-gateway.authorization-grant-type=client_credentials

设置配置以指示您的应用程序需要充当 oauth2 客户端

@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter 

     @Override
     protected void configure(HttpSecurity http) throws Exception 
         http.oauth2Client();
     

公开配置为使用客户端凭据的 WebClient bean

@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
        ClientRegistrationRepository clientRegistrationRepository,
        OAuth2AuthorizedClientRepository authorizedClientRepository) 

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

    DefaultOAuth2AuthorizedClientManager authorizedClientManager =
            new DefaultOAuth2AuthorizedClientManager(
                    clientRegistrationRepository, authorizedClientRepository);
    authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

    return authorizedClientManager;



@Bean
WebClient webClient(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) 
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
            new ServletOAuth2AuthorizedClientExchangeFilterFunction(
                    oAuth2AuthorizedClientManager);
    
    // default registrationId - Only if you are not using the webClient to talk to different external APIs
   oauth2Client.setDefaultClientRegistrationId("ei-gateway");
    
    return WebClient.builder()
      .apply(oauth2Client.oauth2Configuration())
      .build();

现在您可以在代码中使用 WebClient 来访问外部受保护的资源。

参考:

https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2client https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2Client-webclient-servlet https://docs.spring.io/spring-security/site/docs/current/reference/html5/#defaulting-the-authorized-client

当应用程序未配置为资源服务器时,此设置对我有用,当应用程序需要使用 WebClient 时,我必须使用不同的配置,但也配置为资源服务器。

【讨论】:

以上是关于在 Spring MVC 中初始化 OAuth WebClient Bean的主要内容,如果未能解决你的问题,请参考以下文章

Oauth2 授权类型和良好文档的实时示例,Oauth2 与 Spring MVC 的示例

如何将 Oauth2.0 合并到现有的 Java Spring Web MVC 和 REST 项目中?

oauth2 spring-security 如果您在请求令牌或代码之前登录

添加 OAuth2 后 Spring http 安全性停止工作

spring mvc 中可不可以在controller中进行初始化

Spring MVC源码 ----- 启动过程与组件初始化