栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Security源码学习——配置器之WebSecurityConfigurer

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Security源码学习——配置器之WebSecurityConfigurer

前言

SecurityConfigurer 在 Spring Security 中是一个非常重要的角色。Spring Security 过滤器链中的每一个过滤器,都是通过 xxxConfigurer 来进行配置的,而这些 xxxConfigurer 实际上都是 SecurityConfigurer 的实现。

public interface SecurityConfigurer> {

 //一个初始化方法
 void init(B builder) throws Exception;

//一个配置方法。这里只是规范了方法的定义,具体的实现则在不同的实现类中
 void configure(B builder) throws Exception;
}

SecurityConfigurer 有三种类型实现类:SecurityConfigurerAdapter,GlobalAuthenticationConfigurerAdapter和WebSecurityConfigurer

本文主要介绍的是WebSecurityConfigurer

1、WebSecurityConfigurer

public interface WebSecurityConfigurer> extends
		SecurityConfigurer {

}

这里边的泛型很关键,这关乎到 WebSecurityConfigurer 的目的是啥!

SecurityBuilder 中的泛型 Filter,表示 SecurityBuilder 最终的目的是为了构建一个 Filter 对象出来。
SecurityConfigurer 中两个泛型,第一个表示的含义也是 SecurityBuilder 最终构建的对象。
同时这里还定义了新的泛型 T,T 需要继承自 SecurityBuilder,根据 WebSecurityConfigurerAdapter 中的定义,我们可以知道,T 就是 WebSecurity,我们也大概能猜出 WebSecurity 就是 SecurityBuilder 的子类。

所以 WebSecurityConfigurer 的目的我们可以理解为就是为了配置 WebSecurity。

WebSecurityConfigurer的子类图如下

2、WebSecurityConfigurerAdapter 2.1 属性和@Autowired方法
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer {
	
	private ApplicationContext context;
	//提供@Autowired(required = false)方法注入
	private ContentNegotiationStrategy contentNegotiationStrategy = new HeaderContentNegotiationStrategy();

    //通过@Autowired方法注入
	private ObjectPostProcessor objectPostProcessor = new ObjectPostProcessor() {
		public  T postProcess(T object) {
			throw new IllegalStateException(ObjectPostProcessor.class.getName()"");
		}
	};
	//通过@Autowired方法注入
	private AuthenticationConfiguration authenticationConfiguration;
	private AuthenticationManagerBuilder authenticationBuilder;
	private AuthenticationManagerBuilder localConfigureAuthenticationBldr;
	private boolean disableLocalConfigureAuthenticationBldr;
	private boolean authenticationManagerInitialized;
	private AuthenticationManager authenticationManager;
	//提供@Autowired(required = false)方法注入
	private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
	private HttpSecurity http;
	//WebSecurityConfigurerAdapter无参构造器中,设置其为false,是否要关闭WebSecurity的默认设置
	//这里的WebSecurity就是HttpSecurity
	private boolean disableDefaults;
	
     @Autowired
	public void setApplicationContext(ApplicationContext context) {
		this.context = context;
		ObjectPostProcessor objectPostProcessor = context.getBean(ObjectPostProcessor.class);
		//创建密码解析器,注意这里创建的只是一个代理密码解析器,下面有说明
		LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(context);

		authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, passwordEncoder);
		localConfigureAuthenticationBldr = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, passwordEncoder) {
			@Override
			public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
				authenticationBuilder.eraseCredentials(eraseCredentials);
				return super.eraseCredentials(eraseCredentials);
			}

		};
	}

	@Autowired(required = false)
	public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
		this.trustResolver = trustResolver;
	}

	@Autowired(required = false)
	public void setContentNegotationStrategy(ContentNegotiationStrategy contentNegotiationStrategy) {
		this.contentNegotiationStrategy = contentNegotiationStrategy;
	}

	@Autowired
	public void setObjectPostProcessor(ObjectPostProcessor objectPostProcessor) {
		this.objectPostProcessor = objectPostProcessor;
	}

	@Autowired
	public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
		this.authenticationConfiguration = authenticationConfiguration;
	}

}
 
2.1 密码解析器的配置 
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer {

 static class LazyPasswordEncoder implements PasswordEncoder {
		private ApplicationContext applicationContext;
		private PasswordEncoder passwordEncoder;

		LazyPasswordEncoder(ApplicationContext applicationContext) {
			this.applicationContext = applicationContext;
		}

		@Override
		public String encode(CharSequence rawPassword) {
			return getPasswordEncoder().encode(rawPassword);
		}

		@Override
		public boolean matches(CharSequence rawPassword,
			String encodedPassword) {
			return getPasswordEncoder().matches(rawPassword, encodedPassword);
		}

		@Override
		public boolean upgradeEncoding(String encodedPassword) {
			return getPasswordEncoder().upgradeEncoding(encodedPassword);
		}

		private PasswordEncoder getPasswordEncoder() {
			if (this.passwordEncoder != null) {
				return this.passwordEncoder;
			}
			//从容器中创建获取PasswordEncoder对象
			PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
			if (passwordEncoder == null) {
				passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
			}
			this.passwordEncoder = passwordEncoder;
			return passwordEncoder;
		}

		private  T getBeanOrNull(Class type) {
			try {
				return this.applicationContext.getBean(type);
			} catch(NoSuchBeanDefinitionException notFound) {
				return null;
			}
		}

		@Override
		public String toString() {
			return getPasswordEncoder().toString();
		}
	}
}

从上面代码可以看出,PasswordEncoder的创建发生在第一次解析密码时,他先从容器中获取PasswordEncoder对象,如果没有就使用默认的。

如果我要配置我们想要的密码解析器PasswordEncoder,直接在配置类将它加入容器中进行,不需要做额外的操作

2.3 HttpSecurity的初始化过程
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer {

  //HttpSecurity的初始化发生在这里
   public void init(final WebSecurity web) throws Exception {
		final HttpSecurity http = getHttp();
		web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
			FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
			web.securityInterceptor(securityInterceptor);
		});
	}
	
   protected final HttpSecurity getHttp() throws Exception {
		if (http != null) {return http;}

		DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
				.postProcess(new DefaultAuthenticationEventPublisher());
		localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
		//创建AuthenticationManager
		AuthenticationManager authenticationManager = authenticationManager();
		authenticationBuilder.parentAuthenticationManager(authenticationManager);
		authenticationBuilder.authenticationEventPublisher(eventPublisher);
		Map, Object> sharedObjects = createSharedObjects();
		http = new HttpSecurity(objectPostProcessor, authenticationBuilder,sharedObjects);
		if (!disableDefaults) {
			http
				.csrf().and()
				.addFilter(new WebAsyncManagerIntegrationFilter())
				.exceptionHandling().and()
				.headers().and()
				.sessionManagement().and()
				.securityContext().and()
				.requestCache().and()
				.anonymous().and()
				.servletApi().and()
				.apply(new DefaultLoginPageConfigurer<>()).and()
				.logout();
			// @formatter:on
			ClassLoader classLoader = this.context.getClassLoader();
			List defaultHttpConfigurers =
					SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);

			for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
				http.apply(configurer);
			}
		}
		configure(http);
		return http;
	}

   protected void configure(HttpSecurity http) throws Exception {
		http
			.authorizeRequests()
				.anyRequest().authenticated()
				.and()
			.formLogin().and()
			.httpBasic();
	}

}

这里,我们要提下他的这几个方法

public AuthenticationManager authenticationManagerBean() throws Exception {
		return new AuthenticationManagerDelegator(authenticationBuilder, context);
}

protected AuthenticationManager authenticationManager() throws Exception {
	if (!authenticationManagerInitialized) {
	    configure(localConfigureAuthenticationBldr);
		if (disableLocalConfigureAuthenticationBldr) {
			authenticationManager = authenticationConfiguration.getAuthenticationManager();
		}
		else {
			authenticationManager = localConfigureAuthenticationBldr.build();
		}
		authenticationManagerInitialized = true;
	}
	return authenticationManager;
}

	
public UserDetailsService userDetailsServiceBean() throws Exception {
	AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
	return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder));
}

protected UserDetailsService userDetailsService() {
	AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
	return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder));
}
2.3 配置方法
public void configure(WebSecurity web) throws Exception {}

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		
}
protected void configure(HttpSecurity http) throws Exception {		
}
3、WebSecurityConfigurerAdapter的注入位置
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
public class SpringBootWebSecurityConfiguration {

	@Configuration(proxyBeanMethods = false)
	@Order(SecurityProperties.BASIC_AUTH_ORDER)
	static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {

	}

}
转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号