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功能,每个经过那些过滤器都会被展示出来。

SpringSecurity的@EnableWebSecurity注解

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容器初始化的那一整套。

SpringSecurity的@EnableWebSecurity注解

因为我们配置的SpringSecurityConfig这个类,继承了WebSecurityConfigurerAdapter,它又实现了SecurityConfigurer这个接口,所以在配置的时候,能拿到我们这个配置类里面的信息,具体如图:

SpringSecurity的@EnableWebSecurity注解

接着创建过滤器链

//提供一个名叫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里

SpringSecurity的@EnableWebSecurity注解

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

SpringSecurity的@EnableWebSecurity注解

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

SpringSecurity的@EnableWebSecurity注解

SpringSecurity的@EnableWebSecurity注解

上一篇:CV2 之 轮廓检测


下一篇:动态网络下的极致隐匿?NA DFS去中心化存储协议助推NA(Nirvana)Chain成为企业级隐私网络