Spring-Security处理请求的过程

security框架处理请求是从DelegatingFilterProxy#doFilter()方法开始的

// DelegatingFilterProxy.java
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		// Lazily initialize the delegate if necessary.
		Filter delegateToUse = this.delegate;
		if (delegateToUse == null) {
			synchronized (this.delegateMonitor) {
				delegateToUse = this.delegate;
				if (delegateToUse == null) {
					WebApplicationContext wac = findWebApplicationContext();
					if (wac == null) {
						throw new IllegalStateException("No WebApplicationContext found: " +
								"no ContextLoaderListener or DispatcherServlet registered?");
					}
					delegateToUse = initDelegate(wac);
				}
				this.delegate = delegateToUse;
			}
		}

		// Let the delegate perform the actual doFilter operation.
		invokeDelegate(delegateToUse, request, response, filterChain);
	}

其实就是根据注入的targetBeanName(“springSecurityFilterChain”)获取FilterChainProxy,

// DelegatingFilterProxy.java
	protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
		String targetBeanName = getTargetBeanName();
		Assert.state(targetBeanName != null, "No target bean name set");
		Filter delegate = wac.getBean(targetBeanName, Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}

每个请求只能被过滤器过滤一次,使用熟悉FILTER_APPLIED进行标识,然后在doFilterInternal()方法中对请求进行过滤。

// FilterChainProxy.java
	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);
		}
	}

先获取过滤器,使用VirtualFilterChain进行封装,再通过doFilter()方法进行过滤。

// FilterChainProxy.java
	private void doFilterInternal(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
......
		List<Filter> filters = getFilters(fwRequest);
		......
		VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
		vfc.doFilter(fwRequest, fwResponse);
	}

获取过滤器时就是通过属性filterChains(private List filterChains;)获取,

	private List<Filter> getFilters(HttpServletRequest request) {
		for (SecurityFilterChain chain : filterChains) {
			if (chain.matches(request)) {
				return chain.getFilters();
			}
		}

		return null;
	}

filterChains是在WebSecurity#performBuild()方法中赋值的,默认一共有12个过滤器,用

	protected Filter performBuild() throws Exception {
......
		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
			securityFilterChains.add(securityFilterChainBuilder.build());
		}
		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
		......
	}

找到过滤器链后,就会执行每个过滤器的doFilter()方法对请求进行过滤,执行完以后就回到tomcat的过滤器链。

		public void doFilter(ServletRequest request, ServletResponse response)
				throws IOException, ServletException {
                    //如果执行完了就会执行tomcat的过滤器
			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();
                //tomcat过滤器链
				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);
			}
		}

总结一下,security框架对请求的过滤其实就是调用FilterChainProxy封装的过滤器链中的每个过滤器的doFilter()方法,然后回到tomcat的过滤器链路。有不对的地方请大神指出,欢迎大家一起讨论交流,共同进步。

你可能感兴趣的:(spring,java,servlet)