SpringSecurity的@EnableWebSecurity注解
SpringSecurity的@EnableWebSecurity注解
@EnableWebSecurity
@EnableWebSecurity是开启SpringSecurity的默认行为,它的上面有一个Import注解导入了WebSecurityConfiguration类,也就是说我们加上了@EnableWebSecurity这个注解,就是往IOC容器中注入了WebSecurityConfiguration这个类。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class})
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
它还有一个debug的功能,如果设置为true,则开启debug功能,每个经过那些过滤器都会被展示出来。
WebSecurityConfiguration
WebSecurityConfiguration用来配置初始化webSecurity的,在setFilterChainProxySecurityConfigurer方法中,它以配置SpringSecurity时继承自WebSecurityConfigurerAdapter的配置类来初始化SecurityConfigurer列表,来启用所需的安全策略
@Autowired(
required = false
)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor, @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception {
this.webSecurity = (WebSecurity)objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if (this.debugEnabled != null) {
this.webSecurity.debug(this.debugEnabled);
}
webSecurityConfigurers.sort(WebSecurityConfiguration.AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
Object previousConfig = null;
Iterator var5;
SecurityConfigurer config;
for(var5 = webSecurityConfigurers.iterator(); var5.hasNext(); previousConfig = config) {
config = (SecurityConfigurer)var5.next();
Integer order = WebSecurityConfiguration.AnnotationAwareOrderComparator.lookupOrder(config);
if (previousOrder != null && previousOrder.equals(order)) {
throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order + " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");
}
previousOrder = order;
}
var5 = webSecurityConfigurers.iterator();
while(var5.hasNext()) {
config = (SecurityConfigurer)var5.next();
//将配置的每一个SecurityConfigurer列表传递给 webSecurity
this.webSecurity.apply(config);
}
this.webSecurityConfigurers = webSecurityConfigurers;
}
WebSecurityConfiguration这个类的创建流程也是经过spring容器初始化的那一整套。
因为我们配置的SpringSecurityConfig这个类,继承了WebSecurityConfigurerAdapter,它又实现了SecurityConfigurer这个接口,所以在配置的时候,能拿到我们这个配置类里面的信息,具体如图:
接着创建过滤器链
//提供一个名叫springSecurityFilterChain的bean,返回一个Filter对象
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
//如果没有配置过Spring Security,则会议WebSecurityConfigurerAdapter中的配置作为默认,上面能拿到我们的配置,因此就不走这段逻辑
WebSecurityConfigurerAdapter
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
webSecurity.apply(adapter);
}
return webSecurity.build();
}
以前在Spring的配置中,会有一个web.xml,在里面配置过滤器,但是现在SpringBoot已经自动配置了web.xml. DelegatingFilterProxy是Spring提供的一个标准Servlet Filter代理,并代理改bean提供的过滤器,也就是说,在这个配置中,最终起作用的过滤器是什么完全取决于springSecurityFilterChain。
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(SecurityProperties.class)
@ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class })
@AutoConfigureAfter(SecurityAutoConfiguration.class)
public class SecurityFilterAutoConfiguration {
private static final String DEFAULT_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;
@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
SecurityProperties securityProperties) {
DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
DEFAULT_FILTER_NAME);
registration.setOrder(securityProperties.getFilter().getOrder());
registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
return registration;
}
private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) {
if (securityProperties.getFilter().getDispatcherTypes() == null) {
return null;
}
return securityProperties.getFilter().getDispatcherTypes().stream()
.map((type) -> DispatcherType.valueOf(type.name()))
.collect(Collectors.toCollection(() -> EnumSet.noneOf(DispatcherType.class)));
}
}
前面说的springSecurityFilterChain是由 webSecurity.build()这个创建的,最终调用的是doBuild方法,是由AbstractConfiguredSecurityBuilder提供的
public final O build() throws Exception {
if (this.building.compareAndSet(false, true)) {
this.object = doBuild();
return this.object;
}
throw new AlreadyBuiltException("This object has already been built");
}
AbstractConfiguredSecurityBuilder的doBuild调用的是WebSecurity的performBuild()方法
@Override
protected final O doBuild() throws Exception {
synchronized (configurers) {
//安装状态依次执行相应的方法
buildState = BuildState.INITIALIZING;
beforeInit();
//初始化状态,通过调用WebSecurityConfigurerAdapter的init,将所有HttpSecurity添加到WebSecurity里
init();
buildState = BuildState.CONFIGURING;
beforeConfigure();
configure();
buildState = BuildState.BUILDING;
//在BUILDING阶段调用WebSecurity的performBuild方法
O result = performBuild();
buildState = BuildState.BUILT;
return result;
}
}
在init方法中,初始化状态,通过调用WebSecurityConfigurerAdapter的init,将所有HttpSecurity添加到WebSecurity里
在performBuild方法中,SpringSecurity完成了所有过滤器的创建,最终返回一个过滤器链代理类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();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
chainSize);
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
//简单来说,就是每一个HttpSecurity生成一个过滤器链,HttpSecurity则来自我们配置的WebSecurityConfigure
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;
}
filterChainProxy间接继承了FIlter,可以作为真正的过滤器使用,它会携带若干条过滤器链,并在承担过滤器职责时,将其派发到所有过滤器链的每一个过滤器上。
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if (clearContext) {
try {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
doFilterInternal(request, response, chain);
}
finally {
SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
}
else {
doFilterInternal(request, response, chain);
}
}
doFilterInternal是真正执行虚拟过滤器链逻辑的方法
private void doFilterInternal(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//附上Spring Security提供的HTTP防火墙
FirewalledRequest fwRequest = firewall
.getFirewalledRequest((HttpServletRequest) request);
HttpServletResponse fwResponse = firewall
.getFirewalledResponse((HttpServletResponse) response);
//按照配置的RequestMatcher,决定每一个请求会经过那些过滤器
List<Filter> filters = getFilters(fwRequest);
if (filters == null || filters.size() == 0) {
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(fwRequest)
+ (filters == null ? " has no matching filters"
: " has an empty filter list"));
}
fwRequest.reset();
chain.doFilter(fwRequest, fwResponse);
return;
}
//所有的过滤器合并成一条虚拟的过滤器链
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
//模拟过滤器的执行流程,执行整条过滤器链
vfc.doFilter(fwRequest, fwResponse);
}
private static class VirtualFilterChain implements FilterChain {
private final FilterChain originalChain;
private final List<Filter> additionalFilters;
private final FirewalledRequest firewalledRequest;
private final int size;
private int currentPosition = 0;
private VirtualFilterChain(FirewalledRequest firewalledRequest,
FilterChain chain, List<Filter> additionalFilters) {
this.originalChain = chain;
this.additionalFilters = additionalFilters;
this.size = additionalFilters.size();
this.firewalledRequest = firewalledRequest;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if (currentPosition == size) {
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+ " reached end of additional filter chain; proceeding with original chain");
}
// Deactivate path stripping as we exit the security filter chain
this.firewalledRequest.reset();
执行过滤器链后,调用真实的FilterChain,完成原生过滤器的剩余逻辑
originalChain.doFilter(request, response);
}
else {
currentPosition++;
Filter nextFilter = additionalFilters.get(currentPosition - 1);
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+ " at position " + currentPosition + " of " + size
+ " in additional filter chain; firing Filter: '"
+ nextFilter.getClass().getSimpleName() + "'");
}
//通过改变下表回调的方式,按照顺序执行每一个过滤器
nextFilter.doFilter(request, response, this);
}
}
}