Spring Security生效原理

原理

  • SpringSecurity本质是一个排序Filter链(单个类型javax.servlet.Filter的过滤器组成的过滤链),这些链被包装成类型为org.springframework.security.web.DefaultSecurityFilterChain过滤链,是org.springframework.security.web.SecurityFilterChain默认实现类,作用是存放过滤器以及请求匹配规则,本身不能执行过滤逻辑;

  • DefaultSecurityFilterChain通过org.springframework.security.web.FilterChainProxy代理执行,实现逻辑是通过FilterChainProxy#filterChains集合属性存放DefaultSecurityFilterChain,doFilter()方法执行时,从中取出与请求匹配的DefaultSecurityFilterChain,然后遍历执行DefaultSecurityFilterChain中的每个过滤器(通过一个org.springframework.security.web.FilterChainProxy.VirtualFilterChain的内部类(javax.servlet.FilterChain的实现类)递归遍历执行),当FilterChainProxy的中的过滤器执行完毕,即DefaultSecurityFilterChain执行完毕,则继续执行Servlet的过滤器;FilterChainProxy被注册到Spring容器中,beanName 为"springSecurityFilterChain"

  • FilterChainProxy再次被代理,org.springframework.web.filter.DelegatingFilterProxy作为FilterChainProxy的门面被当作Servlet 过滤器添加到Servlet容器中,而DelegatingFilterProxy则通过"springSecurityFilterChain"从Spring容器中获取FilterChainProxy实例,当容器执行到DelegatingFilterProxy过滤器,通过两层代理,最终执行的是过滤链中的过滤器

# FilterChain
public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
# Filter
public interface Filter {
    void init(FilterConfig var1) throws ServletException;

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    void destroy();
}

#
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) {
                                //如果过滤链中的过滤器执行结束,则继续执行Servlet 自己的过滤链
				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();

				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() + "'");
				}
                                //过滤器执行过滤方法,并且将过滤链本身作为参数传进去,过滤器执行完本身的逻辑后调用`chain.doFilter(request, response)`即可递归执行
				nextFilter.doFilter(request, response, this);
			}
		}
	}


# Filter 实例的 doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 方法
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		//... 其他逻辑省略
		chain.doFilter(request, response);
	}

流程

须知:实现org.springframework.web.WebApplicationInitializer的类的onStartup()的会被Servlet容器扫描执行

  • org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer#onStartup
    AbstractSecurityWebApplicationInitializer抽象类 实现WebApplicationInitializer接口
# step 1
public final void onStartup(ServletContext servletContext) throws ServletException {
		beforeSpringSecurityFilterChain(servletContext);
		if (this.configurationClasses != null) {
			AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
			rootAppContext.register(this.configurationClasses);
			servletContext.addListener(new ContextLoaderListener(rootAppContext));
		}
		if (enableHttpSessionEventPublisher()) {
			servletContext.addListener(
					"org.springframework.security.web.session.HttpSessionEventPublisher");
		}
		servletContext.setSessionTrackingModes(getSessionTrackingModes());
		insertSpringSecurityFilterChain(servletContext);
		afterSpringSecurityFilterChain(servletContext);
	}

# step 2
private void insertSpringSecurityFilterChain(ServletContext servletContext) {
                // 指定实际的过滤器,该过滤器即为包装过滤器链"springSecurityFilterChain"
		String filterName = DEFAULT_FILTER_NAME;
                //创建它的代理类
		DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(
				filterName);
		String contextAttribute = getWebApplicationContextAttribute();
		if (contextAttribute != null) {
			springSecurityFilterChain.setContextAttribute(contextAttribute);
		}
                //将该代理过滤器注册进ServletContext
		registerFilter(servletContext, true, filterName, springSecurityFilterChain);
	}

# step 3
private final void registerFilter(ServletContext servletContext,
			boolean insertBeforeOtherFilters, String filterName, Filter filter) {
                //将该代理过滤器添加进ServletContext
		Dynamic registration = servletContext.addFilter(filterName, filter);
		if (registration == null) {
			throw new IllegalStateException(
					"Duplicate Filter registration for '" + filterName
							+ "'. Check to ensure the Filter is only configured once.");
		}
		registration.setAsyncSupported(isAsyncSecuritySupported());
		EnumSet<DispatcherType> dispatcherTypes = getSecurityDispatcherTypes();
		registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters,
				"/*");
	}

  • org.springframework.web.filter.DelegatingFilterProxy#doFilter 代理过滤器执行逻辑
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Filter delegateToUse = this.delegate;
        if (delegateToUse == null) {
            synchronized(this.delegateMonitor) {
                delegateToUse = this.delegate;
                if (delegateToUse == null) {
                    WebApplicationContext wac = this.findWebApplicationContext();
                    if (wac == null) {
                        throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?");
                    }

                    delegateToUse = this.initDelegate(wac);
                }
                //获取目标过滤器“springSecurityFilterChain”
                this.delegate = delegateToUse;
            }
        }
        //调用过滤器执行
        this.invokeDelegate(delegateToUse, request, response, filterChain);
    }

# step 2
  protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        delegate.doFilter(request, response, filterChain);
    }
  • org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration#springSecurityFilterChain
    "springSecurityFilterChain" 实际过滤器的bean注册
 # step 1  AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME 为"springSecurityFilterChain"
	@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);
		}
                //调用方法创建"springSecurityFilterChain",webSecurity初始化在下面 #step 2
		return webSecurity.build();
	}

 # step 2
	@Autowired(required = false)
	public void setFilterChainProxySecurityConfigurer(
			ObjectPostProcessor<Object> objectPostProcessor,
			@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
			throws Exception {
                //objectPostProcessor为AutowireBeanFactoryObjectPostProcessor实例,其postProcess方法实现在#step3
		webSecurity = objectPostProcessor
				.postProcess(new WebSecurity(objectPostProcessor));
		if (debugEnabled != null) {
			webSecurity.debug(debugEnabled);
		}

		Collections.sort(webSecurityConfigurers, AnnotationAwareOrderComparator.INSTANCE);

		Integer previousOrder = null;
		Object previousConfig = null;
		for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
			Integer order = 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;
			previousConfig = config;
		}
		for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
			webSecurity.apply(webSecurityConfigurer);
		}
		this.webSecurityConfigurers = webSecurityConfigurers;
	}
 
# step 3
	public <T> T postProcess(T object) {
		if (object == null) {
			return null;
		}
		T result = null;
		try {
                        //初始化属性
			result = (T) this.autowireBeanFactory.initializeBean(object,
					object.toString());
		}
		catch (RuntimeException e) {
			Class<?> type = object.getClass();
			throw new RuntimeException(
					"Could not postProcess " + object + " of type " + type, e);
		}
		this.autowireBeanFactory.autowireBean(object);
		if (result instanceof DisposableBean) {
			this.disposableBeans.add((DisposableBean) result);
		}
		if (result instanceof SmartInitializingSingleton) {
			this.smartSingletons.add((SmartInitializingSingleton) result);
		}
		return result;
	}
  • org.springframework.security.config.annotation.AbstractSecurityBuilder#build
    该方法创建实际的
# step 1
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");
	}
# step 2 具体创建逻辑
	@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) {
                        //DefaultSecurityFilterChain,保存过滤链
			securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
		}
		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
			//通过HttpSecurity(实现AbstractConfiguredSecurityBuilder接口)创建一个"org.springframework.security.web.DefaultSecurityFilterChain"过滤链添加到securityFilterChains中
                        securityFilterChains.add(securityFilterChainBuilder.build());
		}
                //实际过滤器链"springSecurityFilterChain",类型为"org.springframework.security.web.FilterChainProxy",
		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;
	}
  • org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#doBuild
    是一个模板方法
protected final O doBuild() throws Exception {
		synchronized (configurers) {
			buildState = BuildState.INITIALIZING;

			beforeInit();
			init();

			buildState = BuildState.CONFIGURING;

			beforeConfigure();
			configure();

			buildState = BuildState.BUILDING;

                        //子类个性化实现创建逻辑,具体实现在上一步
			O result = performBuild();

			buildState = BuildState.BUILT;

			return result;
		}
	}
  • org.springframework.security.web.FilterChainProxy#doFilter
 # step 1
	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);
		}
	}

# step 2
	private void doFilterInternal(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {

		FirewalledRequest fwRequest = firewall
				.getFirewalledRequest((HttpServletRequest) request);
		HttpServletResponse fwResponse = firewall
				.getFirewalledResponse((HttpServletResponse) response);

		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;
		}

                //使用org.springframework.security.web.FilterChainProxy.VirtualFilterChain遍历执行过滤器
		VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
		vfc.doFilter(fwRequest, fwResponse);
	}
  • org.springframework.security.web.FilterChainProxy.VirtualFilterChain#doFilter
    VirtualFilterChain遍历递归执行过滤器
		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();

				originalChain.doFilter(request, response);
			}
			else {
                                //初始值为0,每次+1,
				currentPosition++;

                                //从0开始递增获取相应索引的过滤器
				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() + "'");
				}
                                //执行过滤器,this 递归,每个过滤器处理结束后调用chain.doFilter(request, response);触发递归
				nextFilter.doFilter(request, response, this);
			}
		}
	}

过滤器如何添加到springSecurityFilterChain

# step 1 初始化org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration#setFilterChainProxySecurityConfigurer中一些参数
	@Autowired(required = false)
	public void setFilterChainProxySecurityConfigurer(
			ObjectPostProcessor<Object> objectPostProcessor,
                        //标注自动注入数据源
			@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
			throws Exception {
                //创建一个WebSecurity实例,并自动填充属性
		webSecurity = objectPostProcessor
				.postProcess(new WebSecurity(objectPostProcessor));
		if (debugEnabled != null) {
			webSecurity.debug(debugEnabled);
		}

		Collections.sort(webSecurityConfigurers, AnnotationAwareOrderComparator.INSTANCE);

		Integer previousOrder = null;
		Object previousConfig = null;
		for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
			Integer order = 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;
			previousConfig = config;
		}
		for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
                        //将配置文件添加到webSecurity
			webSecurity.apply(webSecurityConfigurer);
		}
		this.webSecurityConfigurers = webSecurityConfigurers;
	}

# step 1.1  从容器中根据类型获取WebSecurityConfigurer.class实例
	public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
		List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<SecurityConfigurer<Filter, WebSecurity>>();
		Map<String, WebSecurityConfigurer> beansOfType = beanFactory
				.getBeansOfType(WebSecurityConfigurer.class);
		for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
			webSecurityConfigurers.add(entry.getValue());
		}
		return webSecurityConfigurers;
	}

# step 2 创建springSecurityFilterChain时调用webSecurity.build()
 AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME 为"springSecurityFilterChain"
	@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);
		}
                //调用方法创建"springSecurityFilterChain"
		return webSecurity.build();
	}
# step 2
  org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#doBuild 
是一个模板方法
protected final O doBuild() throws Exception {
		synchronized (configurers) {
			buildState = BuildState.INITIALIZING;

			beforeInit();
                        //执行配置文件的init()方法,配置文件在# step 1中初始化
			init();

			buildState = BuildState.CONFIGURING;

			beforeConfigure();
			configure();

			buildState = BuildState.BUILDING;

                        //子类个性化实现创建逻辑,具体实现在上一步
			O result = performBuild();

			buildState = BuildState.BUILT;

			return result;
		}
	}

# step 3 org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#init
private void init() throws Exception {
		Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

		for (SecurityConfigurer<O, B> configurer : configurers) {
			configurer.init((B) this);
		}

		for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
			configurer.init((B) this);
		}
	}
  • 上述中的配置文件WebSecurityConfigurer.class(org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter)实例怎么注入到spring容器中的?
    该接口的一个抽象实现为org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
    • 自动配置org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration
@Configuration
@ConditionalOnClass({WebSecurityConfigurerAdapter.class})
@ConditionalOnMissingBean({WebSecurityConfigurerAdapter.class})
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
public class SpringBootWebSecurityConfiguration {
    public SpringBootWebSecurityConfiguration() {
    }

    @Configuration
    @Order(2147483642)
    static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {
        DefaultConfigurerAdapter() {
        }
    }
}
  • 自定义权限管理时使用@EnableWebSecurity注解,该注解也是一个@Configuration
  @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .csrf().disable()
                    .authorizeRequests().mvcMatchers("/user/*", "/login").permitAll()
                    .anyRequest().authenticated()
                    /*.mvcMatchers("/**").hasAuthority("")*/
                    .and().formLogin().successHandler((request, response, authentication) ->
                    System.out.println("登陆成功!"));
        }
    }
  • 配置文件初始化将org.springframework.security.config.annotation.web.builders.HttpSecurity添加到
    org.springframework.security.config.annotation.web.builders.WebSecurity#securityFilterChainBuilders
 # step 1 org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#init
	public void init(final WebSecurity web) throws Exception {
               //或HttpSecurity 没有则创建
		final HttpSecurity http = getHttp();
                //将HttpSecurity作为`org.springframework.security.config.annotation.SecurityBuilder`添加到WebSecurity
		web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
			public void run() {
				FilterSecurityInterceptor securityInterceptor = http
						.getSharedObject(FilterSecurityInterceptor.class);
				web.securityInterceptor(securityInterceptor);
			}
		});
	}

# step 2  创建HttpSecurity,并往里添加过滤器
	protected final HttpSecurity getHttp() throws Exception {
		if (http != null) {
			return http;
		}

		DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
				.postProcess(new DefaultAuthenticationEventPublisher());
		localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);

		AuthenticationManager authenticationManager = authenticationManager();
		authenticationBuilder.parentAuthenticationManager(authenticationManager);
		Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();

               
		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);
			}
		}
		configure(http);
		return http;
	}
  • 再看springSecurityFilterChain的创建过程
 # step 1 org.springframework.security.config.annotation.web.builders.WebSecurity#performBuild
	@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));
		}
		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
                        //具体创建过程调用HttpSecurity#build()
			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;
	}

# step 2 org.springframework.security.config.annotation.web.builders.HttpSecurity#performBuild,可以看出过滤链中有多少过滤器取决于HttpSecurity中定义了多少个过滤器
protected DefaultSecurityFilterChain performBuild() throws Exception {
		Collections.sort(filters, comparator);
		return new DefaultSecurityFilterChain(requestMatcher, filters);
	}


Filter如何添加到HttpSecurity

从上面我们可以直到springSecurityFilterChain中有多少个过滤器完全取决于org.springframework.security.config.annotation.web.builders.HttpSecurity中有多少个过滤器,那么HttpSecurity中的过滤器如何添加进去的?

  • HttpSecurity创建springSecurityFilterChain过程
# step 1 上面提到WebSecurity通过调用HttpSecurity#build()方法创建`springSecurityFilterChain`,而所有的实际执行都是调用org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#doBuild模板方法
	protected final O doBuild() throws Exception {
		synchronized (configurers) {
			buildState = BuildState.INITIALIZING;
                        //初始化前执行
			beforeInit();
                        //遍历调用所有配置的init()方法,
                        //即org.springframework.security.config.annotation.SecurityConfigurer#init
			init();

			buildState = BuildState.CONFIGURING;
                        //配置前执行
			beforeConfigure();
                        //遍历执行所有的配置的配置方法, 
                        //即org.springframework.security.config.annotation.SecurityConfigurer#configure
			configure();

			buildState = BuildState.BUILDING;

                        //实际创建动作,
			O result = performBuild();

			buildState = BuildState.BUILT;

			return result;
		}
	}

# step 2  org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#init
private void init() throws Exception {
		Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

		for (SecurityConfigurer<O, B> configurer : configurers) {
			configurer.init((B) this);
		}

		for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
			configurer.init((B) this);
		}
	}


# step 3 org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#configure
private void configure() throws Exception {
		Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

		for (SecurityConfigurer<O, B> configurer : configurers) {
			configurer.configure((B) this);
		}
	}

# step 4 org.springframework.security.config.annotation.web.builders.HttpSecurity#performBuild
# 所以 `springSecurityFilterChain`实质是通过`org.springframework.security.web.FilterChainProxy`包装
# `org.springframework.security.web.DefaultSecurityFilterChain`代理执行
protected DefaultSecurityFilterChain performBuild() throws Exception {
		Collections.sort(filters, comparator);
		return new DefaultSecurityFilterChain(requestMatcher, filters);
	}
  • 添加Filter
    上面我们知道在创建过程中会执行一个模板方法AbstractConfiguredSecurityBuilder#doBuild,模板方法在执行实际创建方法前会,会优先执行
    AbstractConfiguredSecurityBuilder#initAbstractConfiguredSecurityBuilder#configure,那么HttpSecurity中的Filter应该就是通过这两个方法添加进去的
    • 在了解Filter如何添加进去之前,先了解配置类org.springframework.security.config.annotation.SecurityConfigurer如何添加到HttpSecurity中的
      org.springframework.security.config.annotation.web.builders.HttpSecurity 提供了多种配置方法,让我们可以自由配置各种访问规则或者安全解决方案,每调用一个方法,就会往HttpSecurity中添加一个配置类,如
      org.springframework.security.config.annotation.web.builders.HttpSecurity#headers
      org.springframework.security.config.annotation.web.builders.HttpSecurity#cors
      org.springframework.security.config.annotation.web.builders.HttpSecurity#headers方法为例
# step 1
public HeadersConfigurer<HttpSecurity> headers() throws Exception {
                //添加一个配置类并返回配置类实例,如果Http中已存在该类型的配置类,直接返回
		return getOrApply(new HeadersConfigurer<>());
	}

# step 2
private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(
			C configurer) throws Exception {
		C existingConfig = (C) getConfigurer(configurer.getClass());
		if (existingConfig != null) {
			return existingConfig;
		}
		return apply(configurer);
	}

# step 3
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
			throws Exception {
		configurer.addObjectPostProcessor(objectPostProcessor);
		configurer.setBuilder((B) this);
                //将配置类添加到httpsecurity
		add(configurer);
		return configurer;
	}

# step 4
	private <C extends SecurityConfigurer<O, B>> void add(C configurer) throws Exception {
		Assert.notNull(configurer, "configurer cannot be null");

		Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
				.getClass();
		synchronized (configurers) {
			if (buildState.isConfigured()) {
				throw new IllegalStateException("Cannot apply " + configurer
						+ " to already built object");
			}
			List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
					.get(clazz) : null;
			if (configs == null) {
				configs = new ArrayList<SecurityConfigurer<O, B>>(1);
			}
			configs.add(configurer);
			this.configurers.put(clazz, configs);
			if (buildState.isInitializing()) {
				this.configurersAddedInInitializing.add(configurer);
			}
		}
	}
  • org.springframework.web.filter.OncePerRequestFilter(Filter的抽象实现类)添加到org.springframework.security.config.annotation.web.builders.HttpSecurity#filters
    同样以org.springframework.security.config.annotation.web.builders.HttpSecurity#headers方法为例,该方法会往HttpSecurity中添加一个
    org.springframework.security.config.annotation.web.configurers.HeadersConfigurer配置类实例,以配置类型为key,保存到
    org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder#configurers,同时,HttpSecurity在创建springSecurityFilterChain实例的模板方法AbstractConfiguredSecurityBuilder#doBuild中会去遍历每个配置实例,并调用它们的AbstractConfiguredSecurityBuilder#configure
# step 1 org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
public void configure(H http) throws Exception {
                //将HeaderWriterFilter添加到HttpSecrity中
		HeaderWriterFilter headersFilter = createHeaderWriterFilter();
		http.addFilter(headersFilter);
	}
  • HttpSecurity添加SecurityConfigurer
 # step 1 上面我们知道`org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter`实现会被自动注入或者用户自定义使用` @EnableWebSecurity`注入spring容器,并且
#org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#init方法会被WebSecurity#build()过程调用

# 即 HttpSecurity在被创建时会添加一些配置类

	public void init(final WebSecurity web) throws Exception {
               //或HttpSecurity 没有则创建
		final HttpSecurity http = getHttp();
                //将HttpSecurity作为`org.springframework.security.config.annotation.SecurityBuilder`添加到WebSecurity
		web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
			public void run() {
				FilterSecurityInterceptor securityInterceptor = http
						.getSharedObject(FilterSecurityInterceptor.class);
				web.securityInterceptor(securityInterceptor);
			}
		});
	}

# step 1.1 org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#getHttp
	protected final HttpSecurity getHttp() throws Exception {
		if (http != null) {
			return http;
		}

		DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
				.postProcess(new DefaultAuthenticationEventPublisher());
		localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);

		AuthenticationManager authenticationManager = authenticationManager();
		authenticationBuilder.parentAuthenticationManager(authenticationManager);
		Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();

		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);
			}
		}
		configure(http);
		return http;
	}

# step 2 我们在自定义配置时可能会重写 `org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)`,这样也会添加一些配置类到HttpSecurity中

 @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .csrf().disable()
                    .authorizeRequests().mvcMatchers("/user/*", "/login").permitAll()
                    .anyRequest().authenticated()
                    /*.mvcMatchers("/**").hasAuthority("")*/
                    .and().formLogin().successHandler((request, response, authentication) ->
                    System.out.println("登陆成功!"));
        }
    }

总结

  • WebSecurity 从Spring容器中获取WebSecurityConfigurerAdapter配置类,从配置类中获取HttpSecurity作为SecurityBuilder<DefaultSecurityFilterChain>,用于创建DefaultSecurityFilterChain,并在创建之前执行HttpSecurity中的所有SecurityConfigurer类的init(B builder)方法和configure(B builder)方法

  • HttpSecurity通过提供的方法将SecurityConfigurer添加到AbstractConfiguredSecurityBuilder#configurers中

  • SecurityConfigurer的实现类通过configure(B builder)方法将OncePerRequestFilter添加到HttpSecurity#filters

  • HttpSecurity 通过HttpSecurity#filters创建一个DefaultSecurityFilterChain实例返回给WebSecurity

  • WebSecurity 使用DefaultSecurityFilterChain的实例创建一个FilterChainProxy实例

  • org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration#springSecurityFilterChain方法将FilterChainProxy实例"springSecurityFilterChain"注入到Spring容器中,SpringSecurity的其他自动配置依赖的"springSecurityFilterChain"便从容器中通过约定的beanName获取

总结

WebSecurity用于创建过滤链,由WebSecurityConfiguration创建
HttpSecurity用于配置权限规则,由WebSecurityConfigurerAdapter创建
Security 提供的每个解决方案都有相应的SecurityConfigurer以及Filter(一般通过继承OncePerRequestFilter实现)

SpringSecurity 的原理便是一个FilterChainProxy包装的过滤链,SpringSecurity的自动配置将所有需要Filter添加到该过滤链,使其生效,针对整个过程,扩展思路如下

  • 自定义解决方案,自定义过滤器,将其添加到HttpSecurity中

  • 修改现有方案的,重写过相应过滤器的逻辑

  • 使用Security提供的扩展方法,如一些配置类提供方法支持自定义

posted @ 2022-07-28 12:47  复一日  阅读(291)  评论(0编辑  收藏  举报