springsecurity源码分析

在学习ssm项目时,学习了浅显的部分源码,分享小伙伴,共同进步!

在web.xml中有这样的配置

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>

是否想过filter-name为什么必须写springSecurityFilterChain呢?

其实真正执行的类是DelegatingFilterProxy,继承GenericFilterBean,父类实现Filter,所以关键代码为如何doFilter

public class DelegatingFilterProxy extends GenericFilterBean {
 
  //...
  @Override
	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);
				}
              // 真正做事的是delegate,这个Filter
				this.delegate = delegateToUse;
			}
		}

		// Let the delegate perform the actual doFilter operation.
      // 具体执行方法
		invokeDelegate(delegateToUse, request, response, filterChain);
	}
  
}

这个delegate是如何创建的呢?还是在这个类中

 //...
  private volatile Filter delegate;
// ...
@Override
	protected void initFilterBean() throws ServletException {
		synchronized (this.delegateMonitor) {
			if (this.delegate == null) {
				// If no target bean name specified, use filter name.
				if (this.targetBeanName == null) {
                  // targetBeanName的获取,通过getFilterName方法获取
					this.targetBeanName = getFilterName();
				}
				// Fetch Spring root application context and initialize the delegate early,
				// if possible. If the root application context will be started after this
				// filter proxy, we'll have to resort to lazy initialization.
				WebApplicationContext wac = findWebApplicationContext();
				if (wac != null) {
                  // delegate是通过下边的方法创建的
					this.delegate = initDelegate(wac);
				}
			}
		}
	}

//...
	protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
		String targetBeanName = getTargetBeanName();
		Assert.state(targetBeanName != null, "No target bean name set");
      // 最重要的:delete是通过getBean得到的,参数为targetBeanName,见上个方法
		Filter delegate = wac.getBean(targetBeanName, Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}

而这个getFilterName的代码如下

protected String getFilterName() {
  // 去web.xml里面获取filtername的值,也就是springSecurityFilterChain
		return (this.filterConfig != null ? this.filterConfig.getFilterName() : this.beanName);
	}

delegate的事情解决了,接下来看doFilter里面具体的调用方法invokeDelegate

protected void invokeDelegate(
			Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
// 该方法调用doFilter方法
		delegate.doFilter(request, response, filterChain);
	}

点进去发现是Filter这个接口的方法

    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException;

肯定是具体实现类的doFilter方法,其实是FilterChainProxy这个实现类

@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);
      // if或者else都会执行这个方法
      doFilterInternal(request, response, chain);
    }
    finally {
      SecurityContextHolder.clearContext();
      request.removeAttribute(FILTER_APPLIED);
    }
  }
  else {
    doFilterInternal(request, response, chain);
  }
}

而这个方法代码如下

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

		FirewalledRequest fwRequest = firewall
				.getFirewalledRequest((HttpServletRequest) request);
		HttpServletResponse fwResponse = firewall
				.getFirewalledResponse((HttpServletResponse) response);
		// 获取filter集合,把默认的filter都加载,执行
		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);
	}

到底加载了哪些filter呢?有个SecurityFilters可以查看,包含所有的filter

enum SecurityFilters {
	FIRST(Integer.MIN_VALUE),
	CHANNEL_FILTER,
	SECURITY_CONTEXT_FILTER,
	CONCURRENT_SESSION_FILTER,
	WEB_ASYNC_MANAGER_FILTER /** {@link WebAsyncManagerIntegrationFilter} */,
	HEADERS_FILTER, CORS_FILTER,
	CSRF_FILTER,
	LOGOUT_FILTER,
	X509_FILTER,
	PRE_AUTH_FILTER,
	CAS_FILTER,
	FORM_LOGIN_FILTER,
	OPENID_FILTER,
	LOGIN_PAGE_FILTER,
	DIGEST_AUTH_FILTER,
	BASIC_AUTH_FILTER,
	REQUEST_CACHE_FILTER,
	SERVLET_API_SUPPORT_FILTER,
	JAAS_API_SUPPORT_FILTER,
	REMEMBER_ME_FILTER,
	ANONYMOUS_FILTER,
	SESSION_MANAGEMENT_FILTER,
	EXCEPTION_TRANSLATION_FILTER,
	FILTER_SECURITY_INTERCEPTOR,
	SWITCH_USER_FILTER,
	LAST(Integer.MAX_VALUE);

	private static final int INTERVAL = 100;
	private final int order;

	private SecurityFilters() {
		order = ordinal() * INTERVAL;
	}

	private SecurityFilters(int order) {
		this.order = order;
	}

	public int getOrder() {
		return order;
	}
}

思路再回到起点

springSecurityFilterChain到底是什么时候初始化?怎样初始化呢?

spring-security.xml里面的<security:http>

在导入的jar包坐标spring-security-config里面可以查看,其META-INF里有个spring.handlers配置

点开发现

http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler

需要关注SecurityNamespaceHandler这个类

它的初始化方法

public void init() {
  // 加载解析器
		loadParsers();
	}

具体的解析

private void loadParsers() {
		// Parsers
		parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
		parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
		parsers.put(Elements.LDAP_USER_SERVICE, new LdapUserServiceBeanDefinitionParser());
		parsers.put(Elements.USER_SERVICE, new UserServiceBeanDefinitionParser());
		parsers.put(Elements.JDBC_USER_SERVICE, new JdbcUserServiceBeanDefinitionParser());
		parsers.put(Elements.AUTHENTICATION_PROVIDER,
				new AuthenticationProviderBeanDefinitionParser());
		parsers.put(Elements.GLOBAL_METHOD_SECURITY,
				new GlobalMethodSecurityBeanDefinitionParser());
		parsers.put(Elements.AUTHENTICATION_MANAGER,
				new AuthenticationManagerBeanDefinitionParser());
		parsers.put(Elements.METHOD_SECURITY_METADATA_SOURCE,
				new MethodSecurityMetadataSourceBeanDefinitionParser());

		// Only load the web-namespace parsers if the web classes are available
		if (ClassUtils.isPresent(FILTER_CHAIN_PROXY_CLASSNAME, getClass()
				.getClassLoader())) {
			parsers.put(Elements.DEBUG, new DebugBeanDefinitionParser());
          // 解析器指出HTTP标签的解析类为 HttpSecurityBeanDefinitionParser
			parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
			parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
			parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE,
					new FilterInvocationSecurityMetadataSourceParser());
			parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
			filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
		}

		if (ClassUtils.isPresent(MESSAGE_CLASSNAME, getClass().getClassLoader())) {
			parsers.put(Elements.WEBSOCKET_MESSAGE_BROKER,
					new WebSocketMessageBrokerSecurityBeanDefinitionParser());
		}
	}

进入HttpSecurityBeanDefinitionParser,parse方法具体解析

@Override
	public BeanDefinition parse(Element element, ParserContext pc) {
		CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(
				element.getTagName(), pc.extractSource(element));
		pc.pushContainingComponent(compositeDef);
		// 注册filterChainProxy
		registerFilterChainProxyIfNecessary(pc, pc.extractSource(element));

		// Obtain the filter chains and add the new chain to it
		BeanDefinition listFactoryBean = pc.getRegistry().getBeanDefinition(
				BeanIds.FILTER_CHAINS);
		List<BeanReference> filterChains = (List<BeanReference>) listFactoryBean
				.getPropertyValues().getPropertyValue("sourceList").getValue();
		// 调用createFilterChain
		filterChains.add(createFilterChain(element, pc));

		pc.popAndRegisterContainingComponent();
		return null;
	}

注册的代码如下

static void registerFilterChainProxyIfNecessary(ParserContext pc, Object source) {
		if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
			return;
		}
		// Not already registered, so register the list of filter chains and the
		// FilterChainProxy
		BeanDefinition listFactoryBean = new RootBeanDefinition(ListFactoryBean.class);
		listFactoryBean.getPropertyValues().add("sourceList", new ManagedList());
		pc.registerBeanComponent(new BeanComponentDefinition(listFactoryBean,
				BeanIds.FILTER_CHAINS));

		BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder
				.rootBeanDefinition(FilterChainProxy.class);
		fcpBldr.getRawBeanDefinition().setSource(source);
		fcpBldr.addConstructorArgReference(BeanIds.FILTER_CHAINS);
		fcpBldr.addPropertyValue("filterChainValidator", new RootBeanDefinition(
				DefaultFilterChainValidator.class));
		BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
		pc.registerBeanComponent(new BeanComponentDefinition(fcpBean,
				BeanIds.FILTER_CHAIN_PROXY));
  		// 这个就是注册springSecurityFilterChain
		pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY,
				BeanIds.SPRING_SECURITY_FILTER_CHAIN);
	}

点击后就可以看到

public static final String SPRING_SECURITY_FILTER_CHAIN = "springSecurityFilterChain";

这就是注册的流程

另外再看刚才的另一部分代码

// 调用createFilterChain
filterChains.add(createFilterChain(element, pc));

点开createFilterChain

private BeanReference createFilterChain(Element element, ParserContext pc) {
  // ...
  AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element,
				forceAutoConfig, pc, httpBldr.getSessionCreationPolicy(),
				httpBldr.getRequestCache(), authenticationManager,
				httpBldr.getSessionStrategy(), portMapper, portResolver,
				httpBldr.getCsrfLogoutHandler());
}

点进去查看代码,其构造函数里就定义了各种filter的创建

createAnonymousFilter();
createRememberMeFilter(authenticationManager);
createBasicFilter(authenticationManager);
// 登录表单相关
createFormLoginFilter(sessionStrategy, authenticationManager);
createOpenIDLoginFilter(sessionStrategy, authenticationManager);
createX509Filter(authenticationManager);
createJeeFilter(authenticationManager);
createLogoutFilter();
createLoginPageFilterIfNeeded();
// userDetailsService,还记得吧?
createUserDetailsServiceFactory();
createExceptionTranslationFilter();

猜你喜欢

转载自blog.csdn.net/wjl31802/article/details/89643376