Spring Security

Spring Security

Spring Security是一个提供身份验证、授权和防止常见攻击的框架。

启动过程

以与Spring Boot整合来介绍

  1. SecurityAutoConfiguration自动配置类

classpath路径中存在DefaultAuthenticationEventPublisher类时才加载,加载了一个DefaultAuthenticationEventPublisher类到容器中
导入SpringBootWebSecurityConfiguration(提供默认配置)、WebSecurityEnablerConfiguration(核心)和SecurityDataConfiguration配置类

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)
@EnableConfigurationProperties(SecurityProperties.class)
@Import({ SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class,
		SecurityDataConfiguration.class })
public class SecurityAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean(AuthenticationEventPublisher.class)
	public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
		return new DefaultAuthenticationEventPublisher(publisher);
	}

}
  1. WebSecurityEnablerConfiguration

当不存在名为springSecurityFilterChain的bean时且Web类型为Servlet才加载
@EnableWebSecurity启用Web安全

@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration {

}
  1. @EnableWebSecurity

WebSecurityConfiguration配置类创建了一个名为springSecurityFilterChain的过滤器
@EnableGlobalAuthentication启用全局方法安全注解功能

@Import({ WebSecurityConfiguration.class,
		SpringWebMvcImportSelector.class,
		OAuth2ImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {

	// 是否启用调试,默认false
	boolean debug() default false;
}
  1. WebSecurityConfiguration

注册了AutowiredWebSecurityConfigurersIgnoreParents对象来从beanFactory中获得WebSecurityConfigurer类型的类
在初始化改类时调用setFilterChainProxySecurityConfigurer方法加载环境中的WebSecurityConfigurer,创建WebSecurity类
相关类理解
1.SecurityBuilder: build方法创建对象O
2.SecurityConfigurer<O, B extends SecurityBuilder>:构建者的配置器,用来配置Builder,首先调用init,再调用configure
3.SecurityConfigurerAdapter<O, B extends SecurityBuilder> implements SecurityConfigurer<O, B>:允许子类继承SecurityConfigurer中感兴趣的方法

4.WebSecurityConfigurer<T extends SecurityBuilder> extends SecurityConfigurer<Filter, T>:用于定制WebSecurity
5.WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements SecurityBuilder:用来创建filter

6.AbstractSecurityBuilder通过原子boolean类实现了线程安全
7.AbstractConfiguredSecurityBuilder定义了构建状态及过程

public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
	// 用来构建filter
	private WebSecurity webSecurity;
	// webSecurity的配置信息
	private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
}

Spring Security中filter的创建过程

  1. 自动配置中创建Filter(WebSecurityConfiguration)
public Filter springSecurityFilterChain() throws Exception {
	// 判断当前ioc容器中是否存在WebSecurityConfigurer
	boolean hasConfigurers = webSecurityConfigurers != null
			&& !webSecurityConfigurers.isEmpty();
	// 不存在则使用默认的WebSecurityConfigurerAdapter来配置webSecurity
	if (!hasConfigurers) {
		WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
				.postProcess(new WebSecurityConfigurerAdapter() {
				});
		webSecurity.apply(adapter);
	}
	// 创建filter
	return webSecurity.build();
}
  1. 调用AbstractSecurityBuilder的build方法,CAS判断调用AbstractConfiguredSecurityBuilder的dobuild方法

在默认的WebSecurityConfigurerAdapter中init方法初始了HttpSecurity和FilterSecurityInterceptor对象,configure方法为空

protected final O doBuild() throws Exception {
	synchronized (configurers) {
		// 初始状态
		buildState = BuildState.INITIALIZING;
		// 空方法
		beforeInit();
		
		// 调用WebSecurityConfigurer配置类的init方法配置webSecurity
		init();
		
		// 配置状态
		buildState = BuildState.CONFIGURING;
		// 在HttpSecurity中实现共享对象AuthenticationManager的构建
		beforeConfigure();
		
		// 调用WebSecurityConfigurer配置类的configure方法配置webSecurity
		configure();
		
		// 构建中
		buildState = BuildState.BUILDING;
		// 调用webSecurity的performBuild方法
		O result = performBuild();
		// 构建完成
		buildState = BuildState.BUILT;
		return result;
	}
}
  1. 调用performBuild返回过滤器(WebSecurity)

securityFilterChainBuilders是在上一步的init中添加的
ignoredRequests在上一步的configure方法中添加

protected Filter performBuild() throws Exception {
	···提示
	int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
	// 创建SecurityFilterChain列表
	List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
			chainSize);
	// 添加DefaultSecurityFilterChain类型
	for (RequestMatcher ignoredRequest : ignoredRequests) {
		securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
	}
	// 添加SecurityFilterChain类型
	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;
	···日志
	// 空方法,用于在构建完成后执行
	postBuildAction.run();
	return result;
}
  1. 最终返回的过滤器FilterChainProxy(tomcat中的一个过滤器)

1.如果FilterChainProxy中的filterChains链没有与请求匹配的则调用下一个tomcat中的filter
2.创建VirtualFilterChain来执行在filterChains中第一个满足请求的SecurityFilterChian

public class FilterChainProxy extends GenericFilterBean {
	// 持有的SecurityFilterChain,在上一步中传入构造函数注入
	private List<SecurityFilterChain> filterChains;
	// 防火墙
	private HttpFirewall firewall = new StrictHttpFirewall();
}
private static class VirtualFilterChain implements FilterChain {
	// tomcat中原始的过滤链
	private final FilterChain originalChain;
	// 匹配请求的SecurityFilter
	private final List<Filter> additionalFilters;
	// 当前请求
	private final FirewalledRequest firewalledRequest;
	// 当前过滤器个数
	private final int size;
	// 当前执行位置
	private int currentPosition = 0;
}	

HttpSecurity

作为Spring Boot中自动配置的SecurityFilterChain,当不做其他配置时FilterChainProxy只存在HttpSecurity过滤链。

初始化流程

  1. 在WebSecurity的init方法时调用WebSecurityConfigurerAdapter的init方法
public void init(final WebSecurity web) throws Exception {
	// 创建HttpSecurity
	final HttpSecurity http = getHttp();
	// 将HttpSecurity添加到WebSecurity中,并添加创建完成后的Runnable
	web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
		FilterSecurityInterceptor securityInterceptor = http
				.getSharedObject(FilterSecurityInterceptor.class);
		web.securityInterceptor(securityInterceptor);
	});
}
  1. getHttp方法(WebSecurityConfigurerAdapter)

相关类理解
AuthenticationManagerBuilder:创建AuthenticationManager的构造器
AuthenticationManager:处理身份验证请求,对用户的未授信凭据进行认证
Authentication:表示身份验证请求或身份验证主体在处理请求后的令牌
AuthenticationTrustResolver:用来评估身份验证令牌

protected final HttpSecurity getHttp() throws Exception {
	// 如果存在直接返回
	if (http != null) {
		return http;
	}
	AuthenticationEventPublisher eventPublisher = getAuthenticationEventPublisher();
	localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);

	AuthenticationManager authenticationManager = authenticationManager();
	authenticationBuilder.parentAuthenticationManager(authenticationManager);
	// 放入UserDetailsService、
	Map<Class<?>, Object> sharedObjects = createSharedObjects();
	
	// 通过共享对象和身份验证构造器来创建HttpSecurity
	http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
			sharedObjects);
	// 如果启用默认配置,则添加一些默认的过滤器
	if (!disableDefaults) {
		// @formatter:off
		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<AbstractHttpConfigurer> defaultHttpConfigurers =
				SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);

		for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
			http.apply(configurer);
		}
	}
	// 配置HttpSecurity
	configure(http);
	return http;
}
  1. configure方法(WebSecurityConfigurerAdapter)
protected void configure(HttpSecurity http) throws Exception {
	// 添加两个配置类FormLoginConfigurer和ExpressionUrlAuthorizationConfigurer
	http
		.authorizeRequests()
			.anyRequest().authenticated()
			.and()
		.formLogin().and()
		.httpBasic();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值