一般配置方法(适用于没有SpringSecurity配置时)
@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowCredentials(true); Listlist = Arrays.asList("*"); corsConfiguration.setAllowedHeaders(list); corsConfiguration.setAllowedMethods(list); corsConfiguration.setAllowedOrigins(list); source.registerCorsConfiguration("/**", corsConfiguration); CorsFilter corsFilter = new CorsFilter(source); return corsFilter; } }
SpringSecurity配置时配置方法
@Configuration public class CorsConfig { @Bean public FilterRegistrationBean corsFilterBean() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowCredentials(true); Listlist = Arrays.asList("*"); corsConfiguration.setAllowedHeaders(list); corsConfiguration.setAllowedMethods(list); corsConfiguration.setAllowedOrigins(list); source.registerCorsConfiguration("/**", corsConfiguration); CorsFilter corsFilter = new CorsFilter(source); FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(corsFilter); filterRegistrationBean.setOrder(-101); return filterRegistrationBean; } }
首先说明Spring中过滤器加载使用的是FilterRegistrationBean配置过滤器,FilterRegistrationBean实现了Ordered接口,order排序值默认值为
Ordered.LOWEST_PRECEDENCE=Integer.MAX_VALUE
@Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(SecurityProperties.class) @ConditionalOnClass({AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class}) @AutoConfigureAfter(SecurityAutoConfiguration.class) public class SecurityFilterAutoConfiguration { @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; } }
代码中DEFAULT_FILTER_NAME=“springSecurityFilterChain”,securityProperties.getFilter().getOrder()=-100
@Order注解在没有实现Ordered接口时才生效
查看CorsFilter类可以知道跨域逻辑主要在以下doFilterInternal()方法执行,在此方法添加断点,debug执行,发送请求时未执行此方法,由此判断CorsFilter未执行过滤逻辑
public class CorsFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { CorsConfiguration corsConfiguration = this.configSource.getCorsConfiguration(request); boolean isValid = this.processor.processRequest(corsConfiguration, request, response); if (!isValid || CorsUtils.isPreFlightRequest(request)) { return; } filterChain.doFilter(request, response); } }
找到FilterChain接口,其中有如下doFilter()方法,在此方法添加断点
public interface FilterChain { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException; }
请求时断点停顿处为ApplicationFilterChain,在此类中找到属性ApplicationFilterConfig[] filters,查看filters的值如图
ApplicationFilterChain的方法internalDoFilter()逻辑可以看出filters执行顺序为数组下标升序,而corsFilter位于springSecurityFilterChain的后面,
当执行到springSecurityFilterChain时,springSecurityFilterChain过滤器内部会进行身份校验获取用户信息,如果是跨域请求,用户验证信息会被浏览器拦截,直接中断过滤器执行,
而corsFilter的跨域配置还没有执行到,所以需要配置corsFilter的执行顺序在springSecurityFilterChain之前
public final class ApplicationFilterChain implements FilterChain { private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Call the next filter if there is one if (pos < n) { ApplicationFilterConfig filterConfig = filters[pos++]; try { Filter filter = filterConfig.getFilter(); if (request.isAsyncSupported() && "false".equalsIgnoreCase( filterConfig.getFilterDef().getAsyncSupported())) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } if (Globals.IS_SECURITY_ENABLED) { final ServletRequest req = request; final ServletResponse res = response; Principal principal = ((HttpServletRequest) req).getUserPrincipal(); Object[] args = new Object[]{req, res, this}; SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal); } else { filter.doFilter(request, response, this); } } catch (IOException | ServletException | RuntimeException e) { throw e; } catch (Throwable e) { e = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(e); throw new ServletException(sm.getString("filterChain.filter"), e); } return; } } }
ApplicationFilterChain中filters过滤连的赋值操作,在addFilter()方法中进行,在此方法中添加断点
public final class ApplicationFilterChain implements FilterChain { void addFilter(ApplicationFilterConfig filterConfig) { filters[n++] = filterConfig; } }
请求时可得到如下调用栈
查看ApplicationFilterFactory类的方法createFilterChain()可知,ApplicationFilterConfig由FilterMap生成,而FilterMaps[]
由context(TomcatEmbeddedContext)的findFilterMaps()获取到
public final class ApplicationFilterFactory { public static ApplicationFilterChain createFilterChain(ServletRequest request, Wrapper wrapper, Servlet servlet) { // Acquire the filter mappings for this Context StandardContext context = (StandardContext) wrapper.getParent(); FilterMap filterMaps[] = context.findFilterMaps(); // If there are no filter mappings, we are done if ((filterMaps == null) || (filterMaps.length == 0)) return filterChain; // Acquire the information we will need to match filter mappings DispatcherType dispatcher = (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); String requestPath = null; Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR); if (attribute != null) { requestPath = attribute.toString(); } String servletName = wrapper.getName(); for (FilterMap filterMap : filterMaps) { if (!matchDispatcher(filterMap, dispatcher)) { continue; } if (!matchFiltersURL(filterMap, requestPath)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMap.getFilterName()); if (filterConfig == null) { // FIXME - log configuration problem continue; } filterChain.addFilter(filterConfig); } } }
进入findFilterMaps()(此方法为TomcatEmbeddedContext继承自StandardContext的)处在StandardContext类中,分析可知FilterMap[]
由filterMaps生成,而filterMaps由addFilterMapBefore()和addFilterMap()方法添加,在两个方法添加断点
public class StandardContext extends ContainerBase implements Context, NotificationEmitter { @Override public FilterMap[] findFilterMaps() { return filterMaps.asArray(); } @Override public void addFilterMapBefore(FilterMap filterMap) { validateFilterMap(filterMap); // Add this filter mapping to our registered set filterMaps.addBefore(filterMap); fireContainerEvent("addFilterMap", filterMap); } @Override public void addFilterMap(FilterMap filterMap) { validateFilterMap(filterMap); // Add this filter mapping to our registered set filterMaps.add(filterMap); fireContainerEvent("addFilterMap", filterMap); } }
请求时断点停顿处,其调用栈如下
进入addMappingForUrlPatterns()方法,分析FilterMap由filterDef生成,而filterDef由setInitParameter()方法和ApplicationFilterRegistration()
构造方法控制,在方法添加断点
public class ApplicationFilterRegistration implements FilterRegistration.Dynamic { public ApplicationFilterRegistration(FilterDef filterDef, Context context) { this.filterDef = filterDef; this.context = context; } @Override public void addMappingForUrlPatterns( EnumSetdispatcherTypes, boolean isMatchAfter, String... urlPatterns) { FilterMap filterMap = new FilterMap(); filterMap.setFilterName(filterDef.getFilterName()); if (dispatcherTypes != null) { for (DispatcherType dispatcherType : dispatcherTypes) { filterMap.setDispatcher(dispatcherType.name()); } } if (urlPatterns != null) { // % decoded (if necessary) using UTF-8 for (String urlPattern : urlPatterns) { filterMap.addURLPattern(urlPattern); } if (isMatchAfter) { context.addFilterMap(filterMap); } else { context.addFilterMapBefore(filterMap); } } // else error? } @Override public boolean setInitParameter(String name, String value) { if (name == null || value == null) { throw new IllegalArgumentException( sm.getString("applicationFilterRegistration.nullInitParam", name, value)); } if (getInitParameter(name) != null) { return false; } filterDef.addInitParameter(name, value); return true; } }
请求时断点停顿,调用栈为
进入addFilter()方法,使用evaluate expression计算器分析context.findFilterDef(filterName)为null,filterDef为filterName赋值
public class ApplicationContext implements ServletContext { private FilterRegistration.Dynamic addFilter(String filterName, String filterClass, Filter filter) throws IllegalStateException { FilterDef filterDef = context.findFilterDef(filterName); // Assume a 'complete' FilterRegistration is one that has a class and // a name if (filterDef == null) { filterDef = new FilterDef(); filterDef.setFilterName(filterName); context.addFilterDef(filterDef); } else { if (filterDef.getFilterName() != null && filterDef.getFilterClass() != null) { return null; } } return new ApplicationFilterRegistration(filterDef, context); } }
再次查看调用栈,分析可知filterName来源于addRegistration()方法
public abstract class AbstractFilterRegistrationBeanextends DynamicRegistrationBean { @Override protected Dynamic addRegistration(String description, ServletContext servletContext) { Filter filter = getFilter(); return servletContext.addFilter(getOrDeduceName(filter), filter); } }
进入addRegistration()方法分析知道filter来自getFilter()
,且this类型为FilterRegistrationBean,进入FilterRegistrationBean的getFilter()方法,返回为this.filter,查找filter的赋值操作setFilter()
方法和FilterRegistrationBean()构造方法,添加断点
public class FilterRegistrationBeanextends AbstractFilterRegistrationBean { @Override public T getFilter() { return this.filter; } public FilterRegistrationBean(T filter, ServletRegistrationBean>... servletRegistrationBeans) { super(servletRegistrationBeans); Assert.notNull(filter, "Filter must not be null"); this.filter = filter; } public void setFilter(T filter) { Assert.notNull(filter, "Filter must not be null"); this.filter = filter; } }
请求时断点停顿,分析调用栈找到FilterRegistrationBean的filter赋值操作的源头为addAsRegistrationBean()方法
进入addAsRegistrationBean()方法,可以看到RegistrationBean的创建,并且设置排序属性值,最后将FilterRegistrationBean存入this.initializers
public class ServletContextInitializerBeans extends AbstractCollection{ @SafeVarargs public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class extends ServletContextInitializer>... initializerTypes) { this.initializers = new LinkedMultiValueMap<>(); this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes) : Collections.singletonList(ServletContextInitializer.class); addServletContextInitializerBeans(beanFactory); addAdaptableBeans(beanFactory); List sortedInitializers = this.initializers.values().stream() .flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE)) .collect(Collectors.toList()); this.sortedList = Collections.unmodifiableList(sortedInitializers); logMappings(this.initializers); } private void addAsRegistrationBean(ListableBeanFactory beanFactory, Class type, Class beanType, RegistrationBeanAdapter adapter) { List > entries = getOrderedBeansOfType(beanFactory, beanType, this.seen); for (Entry entry : entries) { String beanName = entry.getKey(); B bean = entry.getValue(); if (this.seen.add(bean)) { // One that we haven't already seen RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size()); int order = getOrder(bean); registration.setOrder(order); this.initializers.add(type, registration); if (logger.isTraceEnabled()) { logger.trace("Created " + type.getSimpleName() + " initializer for bean '" + beanName + "'; order=" + order + ", resource=" + getResourceDescription(beanName, beanFactory)); } } } } }
分析this.initializers的操作,没有直接取值的操作,但在ServletContextInitializerBeans()构造函数中间接赋值给了this.sortedList,而查看调用栈也可以得知
而this.initializers向this.sortedList赋值时最重要操作是如下代码:
将所有AbstractFilterRegistrationBean按照AnnotationAwareOrderComparator的规则进行排序,因为此类型实现了Ordered接口所以优先按照接口排序值排序,当没有实现Ordered接口时才按照@Order注解排序,
然后转换为不可修改的集合赋值给this.sortedList
ListsortedInitializers=this.initializers.values().stream() .flatMap((value)->value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE)) .collect(Collectors.toList()); this.sortedList=Collections.unmodifiableList(sortedInitializers);
在ServletContextInitializerBeans类中找到this.sortedList的操作,iterator()方法添加断点
public class ServletContextInitializerBeans extends AbstractCollection{ @Override public Iterator iterator() { return this.sortedList.iterator(); } }
放开上一个断点,进入iterator(),查看调用栈
在selfInitialize()方法内getServletContextInitializerBeans()获取到this.sortedList,即排序后的FilterRegistrationBean,按照顺序挨个执行
public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext { private void selfInitialize(ServletContext servletContext) throws ServletException { prepareWebApplicationContext(servletContext); registerApplicationScope(servletContext); WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext); for (ServletContextInitializer beans : getServletContextInitializerBeans()) { beans.onStartup(servletContext); } } }