SPRING与设计模式---生成器模式
使用场景:当一个产品(对象)构造过程很复杂时,使用生成器模式封装产品的构造过程,并允许按步骤构造。
springsecurity4构造FilterChainProxy并添加到容器中的过程
1.使用HttpSecurity构造DefaultSecurityFilterChain就使用到了生成器模式,见UML类图:
源码:使用FilterComparator对filters进行排序,然后生成DefaultSecurityFilterChain
@Override protected DefaultSecurityFilterChain performBuild() throws Exception { Collections.sort(filters, comparator); return new DefaultSecurityFilterChain(requestMatcher, filters); }
2.最终由WebSecurity使用生成器模式生成FilterChainProxy,并将DefaultSecurityFilterChain注入FilterChainProxy中。
@Override protected Filter performBuild() throws Exception { Assert.state( !securityFilterChainBuilders.isEmpty(), "At least one SecurityBuilder extends SecurityFilterChain> needs to be specified. Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. More advanced users can invoke " + WebSecurity.class.getSimpleName() + ".addSecurityFilterChainBuilder directly"); int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size(); ListsecurityFilterChains = new ArrayList ( chainSize); for (RequestMatcher ignoredRequest : ignoredRequests) { securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest)); } for (SecurityBuilder extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) { securityFilterChains.add(securityFilterChainBuilder.build()); } FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains); if (httpFirewall != null) { filterChainProxy.setFirewall(httpFirewall); } filterChainProxy.afterPropertiesSet(); Filter result = filterChainProxy; if (debugEnabled) { logger.warn("\n\n" + "********************************************************************\n" + "********** Security debugging is enabled. *************\n" + "********** This may include sensitive information. *************\n" + "********** Do not use in a production system! *************\n" + "********************************************************************\n\n"); result = new DebugFilter(filterChainProxy); } postBuildAction.run(); return result; }
3.WebSecurityConfiguration使用WebSecurity生成FilterChainProxy的注入SPRING容器
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) public Filter springSecurityFilterChain() throws Exception { boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty(); if (!hasConfigurers) { WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor .postProcess(new WebSecurityConfigurerAdapter() { }); webSecurity.apply(adapter); } return webSecurity.build(); }
由于生成器类(都是以Builder结尾的类名)要做的事情很多,而且都不相同,所以有一堆配置器类(以Configurer结尾的类)来完成各个Filter的生成。UML类图见:
配置代码:
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private AccessDeniedHandler accessDeniedHandler; // roles admin allow to access /admin/** // roles user allow to access /user/** // custom 403 access denied handler @Override protected void configure(HttpSecurity http) throws Exception { // fix X-Frame-Options:DENY http.headers().frameOptions().disable(); http.csrf().disable() .authorizeRequests() .antMatchers("/", "/home", "/about",UserSignAuthenticationFilter.USER_SIGN_LOGIN_URL).permitAll() // .antMatchers("/admin/**").hasAnyRole("ADMIN") // .antMatchers("/user/**").hasAnyRole("USER") .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll() .and() .exceptionHandling().accessDeniedHandler(accessDeniedHandler); //自定义身份认证方式, http.addFilterBefore(buildUserSignAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); //自定义授权方式 http.addFilterBefore(buildProtectedUrlFilter(), FilterSecurityInterceptor.class); }