浏览代码

Improve message for NoUniqueBeanDefinitionException in OAuth2ClientConfigurerUtils

Joe Grandja 7 年之前
父节点
当前提交
ec970c9b8e

+ 14 - 2
config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerUtils.java

@@ -16,6 +16,7 @@
 package org.springframework.security.config.annotation.web.configurers.oauth2.client;
 
 import org.springframework.beans.factory.BeanFactoryUtils;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
@@ -23,6 +24,7 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
 import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;
 import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
 import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
+import org.springframework.util.StringUtils;
 
 import java.util.Map;
 
@@ -47,7 +49,16 @@ final class OAuth2ClientConfigurerUtils {
 	}
 
 	private static <B extends HttpSecurityBuilder<B>> ClientRegistrationRepository getClientRegistrationRepositoryBean(B builder) {
-		return builder.getSharedObject(ApplicationContext.class).getBean(ClientRegistrationRepository.class);
+		Map<String, ClientRegistrationRepository> clientRegistrationRepositoryMap = BeanFactoryUtils.beansOfTypeIncludingAncestors(
+				builder.getSharedObject(ApplicationContext.class), ClientRegistrationRepository.class);
+		if (clientRegistrationRepositoryMap.isEmpty()) {
+			throw new NoSuchBeanDefinitionException(ClientRegistrationRepository.class);
+		} else if (clientRegistrationRepositoryMap.size() > 1) {
+			throw new NoUniqueBeanDefinitionException(ClientRegistrationRepository.class, clientRegistrationRepositoryMap.size(),
+					"Expected single matching bean of type '" + ClientRegistrationRepository.class.getName() + "' but found " +
+							clientRegistrationRepositoryMap.size() + ": " + StringUtils.collectionToCommaDelimitedString(clientRegistrationRepositoryMap.keySet()));
+		}
+		return clientRegistrationRepositoryMap.values().iterator().next();
 	}
 
 	static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizedClientService getAuthorizedClientService(B builder) {
@@ -67,7 +78,8 @@ final class OAuth2ClientConfigurerUtils {
 				builder.getSharedObject(ApplicationContext.class), OAuth2AuthorizedClientService.class);
 		if (authorizedClientServiceMap.size() > 1) {
 			throw new NoUniqueBeanDefinitionException(OAuth2AuthorizedClientService.class, authorizedClientServiceMap.size(),
-				"Only one matching @Bean of type " + OAuth2AuthorizedClientService.class.getName() + " should be registered.");
+				"Expected single matching bean of type '" + OAuth2AuthorizedClientService.class.getName() + "' but found " +
+					authorizedClientServiceMap.size() + ": " + StringUtils.collectionToCommaDelimitedString(authorizedClientServiceMap.keySet()));
 		}
 		return (!authorizedClientServiceMap.isEmpty() ? authorizedClientServiceMap.values().iterator().next() : null);
 	}

+ 67 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfigurationTests.java

@@ -17,6 +17,7 @@ package org.springframework.security.config.annotation.web.configuration;
 
 import org.junit.Rule;
 import org.junit.Test;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
@@ -101,7 +102,8 @@ public class OAuth2ClientConfigurationTests {
 	public void loadContextWhenOAuth2AuthorizedClientServiceRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
 		assertThatThrownBy(() -> this.spring.register(OAuth2AuthorizedClientServiceRegisteredTwiceConfig.class).autowire())
 				.hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class)
-				.hasMessageContaining("Only one matching @Bean of type " + OAuth2AuthorizedClientService.class.getName() + " should be registered.");
+				.hasMessageContaining("Expected single matching bean of type '" + OAuth2AuthorizedClientService.class.getName() +
+					"' but found 2: authorizedClientService1,authorizedClientService2");
 	}
 
 	@EnableWebMvc
@@ -110,11 +112,13 @@ public class OAuth2ClientConfigurationTests {
 
 		@Override
 		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
 			http
 				.authorizeRequests()
 					.anyRequest().authenticated()
 					.and()
 				.oauth2Login();
+			// @formatter:on
 		}
 
 		@Bean
@@ -132,4 +136,66 @@ public class OAuth2ClientConfigurationTests {
 			return mock(OAuth2AuthorizedClientService.class);
 		}
 	}
+
+	@Test
+	public void loadContextWhenClientRegistrationRepositoryNotRegisteredThenThrowNoSuchBeanDefinitionException() {
+		assertThatThrownBy(() -> this.spring.register(ClientRegistrationRepositoryNotRegisteredConfig.class).autowire())
+				.hasRootCauseInstanceOf(NoSuchBeanDefinitionException.class)
+				.hasMessageContaining("No qualifying bean of type '" + ClientRegistrationRepository.class.getName() + "' available");
+	}
+
+	@EnableWebMvc
+	@EnableWebSecurity
+	static class ClientRegistrationRepositoryNotRegisteredConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().authenticated()
+					.and()
+				.oauth2Login();
+			// @formatter:on
+		}
+	}
+
+	@Test
+	public void loadContextWhenClientRegistrationRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
+		assertThatThrownBy(() -> this.spring.register(ClientRegistrationRepositoryRegisteredTwiceConfig.class).autowire())
+				.hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class)
+				.hasMessageContaining("Expected single matching bean of type '" + ClientRegistrationRepository.class.getName() +
+						"' but found 2: clientRegistrationRepository1,clientRegistrationRepository2");
+	}
+
+	@EnableWebMvc
+	@EnableWebSecurity
+	static class ClientRegistrationRepositoryRegisteredTwiceConfig extends WebSecurityConfigurerAdapter {
+
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeRequests()
+					.anyRequest().authenticated()
+					.and()
+				.oauth2Login();
+			// @formatter:on
+		}
+
+		@Bean
+		public ClientRegistrationRepository clientRegistrationRepository1() {
+			return mock(ClientRegistrationRepository.class);
+		}
+
+		@Bean
+		public ClientRegistrationRepository clientRegistrationRepository2() {
+			return mock(ClientRegistrationRepository.class);
+		}
+
+		@Bean
+		public OAuth2AuthorizedClientService authorizedClientService() {
+			return mock(OAuth2AuthorizedClientService.class);
+		}
+	}
 }