《设计模式》建造者模式 (spring-security-oauth2源码之ClientDetailsServiceConfigurer)

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

简单版参照

https://blog.csdn.net/u010102390/article/details/80179754

看下spring-security-oauth2是怎么玩的

1.首先定义总的Configurer类--ClientDetailsServiceConfigurer 。 友情提示,所有生成配置的类都是以Configurer结尾。

此类持有ClientDetailsServiceBuilder  ,ClientDetailsServiceBuilder的子类负责通过ClientBuilder创建Client

/**
 * @author Rob Winch
 * 
 */
public class ClientDetailsServiceConfigurer extends
		SecurityConfigurerAdapter<ClientDetailsService, ClientDetailsServiceBuilder<?>> {

	public ClientDetailsServiceConfigurer(ClientDetailsServiceBuilder<?> builder) {
		setBuilder(builder);
	}

	public ClientDetailsServiceBuilder<?> withClientDetails(ClientDetailsService clientDetailsService) throws Exception {
		setBuilder(getBuilder().clients(clientDetailsService));
		return this.and();
	}

	public InMemoryClientDetailsServiceBuilder inMemory() throws Exception {
		InMemoryClientDetailsServiceBuilder next = getBuilder().inMemory();
		setBuilder(next);
		return next;
	}
	public JdbcClientDetailsServiceBuilder jdbc(DataSource dataSource) throws Exception {
		JdbcClientDetailsServiceBuilder next = getBuilder().jdbc().dataSource(dataSource);
		setBuilder(next);
		return next;
	}
	
	@Override
	public void init(ClientDetailsServiceBuilder<?> builder) throws Exception {
	}

	@Override
	public void configure(ClientDetailsServiceBuilder<?> builder) throws Exception {
	}

}

InMemoryClientDetailsServiceBuilder为例

public class InMemoryClientDetailsServiceBuilder extends
		ClientDetailsServiceBuilder<InMemoryClientDetailsServiceBuilder> {

	private Map<String, ClientDetails> clientDetails = new HashMap<String, ClientDetails>();

	@Override
	protected void addClient(String clientId, ClientDetails value) {
		clientDetails.put(clientId, value);
	}

	@Override
	protected ClientDetailsService performBuild() {
		InMemoryClientDetailsService clientDetailsService = new InMemoryClientDetailsService();
		clientDetailsService.setClientDetailsStore(clientDetails);
		return clientDetailsService;
	}

}

继承ClientDetailsServiceBuilder  

持有private List<ClientBuilder> clientBuilders = new ArrayList<ClientBuilder>();   保存了所有客户端信息配置。

public class ClientDetailsServiceBuilder<B extends ClientDetailsServiceBuilder<B>> extends
		SecurityConfigurerAdapter<ClientDetailsService, B> implements SecurityBuilder<ClientDetailsService> {

	private List<ClientBuilder> clientBuilders = new ArrayList<ClientBuilder>();

	public InMemoryClientDetailsServiceBuilder inMemory() throws Exception {
		return new InMemoryClientDetailsServiceBuilder();
	}

	public JdbcClientDetailsServiceBuilder jdbc() throws Exception {
		return new JdbcClientDetailsServiceBuilder();
	}

	@SuppressWarnings("rawtypes")
	public ClientDetailsServiceBuilder<?> clients(final ClientDetailsService clientDetailsService) throws Exception {
		return new ClientDetailsServiceBuilder() {
			@Override
			public ClientDetailsService build() throws Exception {
				return clientDetailsService;
			}
		};
	}

   //设置Client并把其放到list
	public ClientBuilder withClient(String clientId) {
		ClientBuilder clientBuilder = new ClientBuilder(clientId);
		this.clientBuilders.add(clientBuilder);
		return clientBuilder;
	}

    。。。。。。。。。。。。。。。
}

ClientBuilder 配置组装client, 是内部类

	public final class ClientBuilder {
		private final String clientId;

		private Collection<String> authorizedGrantTypes = new LinkedHashSet<String>();

		private Collection<String> authorities = new LinkedHashSet<String>();

		private Integer accessTokenValiditySeconds;

		private Integer refreshTokenValiditySeconds;

		private Collection<String> scopes = new LinkedHashSet<String>();

		private Collection<String> autoApproveScopes = new HashSet<String>();

		private String secret;

		private Set<String> registeredRedirectUris = new HashSet<String>();

		private Set<String> resourceIds = new HashSet<String>();

		private boolean autoApprove;

		private Map<String, Object> additionalInformation = new LinkedHashMap<String, Object>();

		private ClientDetails build() {
			BaseClientDetails result = new BaseClientDetails();
			result.setClientId(clientId);
			result.setAuthorizedGrantTypes(authorizedGrantTypes);
			result.setAccessTokenValiditySeconds(accessTokenValiditySeconds);
			result.setRefreshTokenValiditySeconds(refreshTokenValiditySeconds);
			result.setRegisteredRedirectUri(registeredRedirectUris);
			result.setClientSecret(secret);
			result.setScope(scopes);
			result.setAuthorities(AuthorityUtils.createAuthorityList(authorities.toArray(new String[authorities.size()])));
			result.setResourceIds(resourceIds);
			result.setAdditionalInformation(additionalInformation);
			if (autoApprove) {
				result.setAutoApproveScopes(scopes);
			}
			else {
				result.setAutoApproveScopes(autoApproveScopes);
			}
			return result;
		}

		public ClientBuilder resourceIds(String... resourceIds) {
			for (String resourceId : resourceIds) {
				this.resourceIds.add(resourceId);
			}
			return this;
		}

		public ClientBuilder redirectUris(String... registeredRedirectUris) {
			for (String redirectUri : registeredRedirectUris) {
				this.registeredRedirectUris.add(redirectUri);
			}
			return this;
		}

		public ClientBuilder authorizedGrantTypes(String... authorizedGrantTypes) {
			for (String grant : authorizedGrantTypes) {
				this.authorizedGrantTypes.add(grant);
			}
			return this;
		}

		public ClientBuilder accessTokenValiditySeconds(int accessTokenValiditySeconds) {
			this.accessTokenValiditySeconds = accessTokenValiditySeconds;
			return this;
		}

		public ClientBuilder refreshTokenValiditySeconds(int refreshTokenValiditySeconds) {
			this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
			return this;
		}

		public ClientBuilder secret(String secret) {
			this.secret = secret;
			return this;
		}

		public ClientBuilder scopes(String... scopes) {
			for (String scope : scopes) {
				this.scopes.add(scope);
			}
			return this;
		}

		public ClientBuilder authorities(String... authorities) {
			for (String authority : authorities) {
				this.authorities.add(authority);
			}
			return this;
		}

		public ClientBuilder autoApprove(boolean autoApprove) {
			this.autoApprove = autoApprove;
			return this;
		}

		public ClientBuilder autoApprove(String... scopes) {
			for (String scope : scopes) {
				this.autoApproveScopes.add(scope);
			}
			return this;
		}

		public ClientBuilder additionalInformation(Map<String, ?> map) {
			this.additionalInformation.putAll(map);
			return this;
		}

		public ClientBuilder additionalInformation(String... pairs) {
			for (String pair : pairs) {
				String separator = ":";
				if (!pair.contains(separator) && pair.contains("=")) {
					separator = "=";
				}
				int index = pair.indexOf(separator);
				String key = pair.substring(0, index > 0 ? index : pair.length());
				String value = index > 0 ? pair.substring(index+1) : null;
				this.additionalInformation.put(key, (Object) value);
			}
			return this;
		}

		public ClientDetailsServiceBuilder<B> and() {
			return ClientDetailsServiceBuilder.this;
		}

		private ClientBuilder(String clientId) {
			this.clientId = clientId;
		}

	}

4. ClientDetailsServiceConfiguration 依据配置创建ClientDetailsService

@Configuration
public class ClientDetailsServiceConfiguration {

	@SuppressWarnings("rawtypes")
	private ClientDetailsServiceConfigurer configurer = new ClientDetailsServiceConfigurer(new ClientDetailsServiceBuilder());
	
	@Bean
	public ClientDetailsServiceConfigurer clientDetailsServiceConfigurer() {
		return configurer;
	}

	@Bean
	@Lazy
	@Scope(proxyMode=ScopedProxyMode.INTERFACES)
	public ClientDetailsService clientDetailsService() throws Exception {
		return configurer.and().build();
	}

}

看下build方法

public class ClientDetailsServiceBuilder<B extends ClientDetailsServiceBuilder<B>> extends
		SecurityConfigurerAdapter<ClientDetailsService, B> implements SecurityBuilder<ClientDetailsService> {

	private List<ClientBuilder> clientBuilders = new ArrayList<ClientBuilder>();

.................................................................
	@Override
	public ClientDetailsService build() throws Exception {
		for (ClientBuilder clientDetailsBldr : clientBuilders) {
			addClient(clientDetailsBldr.clientId, clientDetailsBldr.build());
		}
		return performBuild();
	}
....................................................................
}

 

 

 看下类图

 

 

 

好了,看一下实际代码中, 我们是怎么用它的.

 

@Configuration
@EnableAuthorizationServer
public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{

	@Autowired
	private ClientService clientService;
	
	
	/**
	 * 配置能sso登陆的客户端
	 */
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		//放在内存
		InMemoryClientDetailsServiceBuilder builder = clients.inMemory(); 
		
		//获取所有client
		List<Client> list=clientService.findAll();
		
		
		for(Client config:list) {
			
			String scopesStr=ClientDeafaultConstant.SCOPES;;
			
			String authorizedGrantTypesStr=null;
			Long accessTokenValiditySeconds=3600L;
			
			if(!StringsUtils.hasText(authorizedGrantTypesStr)) {
				authorizedGrantTypesStr=ClientDeafaultConstant.AUTHORIZED_GRANT_TYPES;
			}else {
				authorizedGrantTypesStr=config.getAuthorizedGrantTypes();
			}
			if(0==config.getAccessTokenValiditySeconds()) {
				accessTokenValiditySeconds=ClientDeafaultConstant.ACCESSTOKEN_VAILDITY_SECONDS;
			}else {
				accessTokenValiditySeconds=config.getAccessTokenValiditySeconds();
			}
			String[] authorizedGrantTypes=StringUtils.splitByWholeSeparatorPreserveAllTokens(authorizedGrantTypesStr, StringsUtils.COMMA);
			String[] scopes=StringUtils.splitByWholeSeparatorPreserveAllTokens(scopesStr,StringsUtils.COMMA);
			
			
			//构建client信息
			builder.withClient(config.getClientKey())
			.secret(config.getClientSecret())
			.accessTokenValiditySeconds(accessTokenValiditySeconds.intValue())
			.authorizedGrantTypes(authorizedGrantTypes)
			.autoApprove(true)
			.scopes(scopes);
		}

	}
..........................................................
}

 

©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页