spring security之DelegatingFilterProxy和FilterChainProxy
来源:互联网 发布:城市公园命名数据库 编辑:程序博客网 时间:2024/06/06 16:29
DelegatingFilterProxy
DelegatingFilterProxy类是一个spring类,位于org.springframework.web jar包下,这个类本身是和spring security无关。该类继承与抽象类GenericFilterBean,间接地实现了javax.servlet.Filter接口,Servlet容器在启动时,首先会调用Filter的init方法,GenericFilterBean的作用主要是可以把Filter的初始化参数自动地set到继承与GenericFilterBean类的Filter中区。其源码如下:
public final void init(FilterConfig filterConfig) throws ServletException {Assert.notNull(filterConfig, "FilterConfig must not be null");if (logger.isDebugEnabled()) {logger.debug("Initializing filter '" + filterConfig.getFilterName() + "'");}this.filterConfig = filterConfig;// Set bean properties from init parameters.try {PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));initBeanWrapper(bw);bw.setPropertyValues(pvs, true);}catch (BeansException ex) {String msg = "Failed to set bean properties on filter '" +filterConfig.getFilterName() + "': " + ex.getMessage();logger.error(msg, ex);throw new NestedServletException(msg, ex);}// Let subclasses do whatever initialization they like.initFilterBean();if (logger.isDebugEnabled()) {logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");}}在该方法中调用了initFilterBean()方法,该方法是GenericFilterBean类特地留给子类扩展使用的。其实现在DelegatingFilterProxy中
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) {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) {this.delegate = initDelegate(wac);}}}}可以看出上述代码首先看Filter是否提供了targetBeanName初始化参数,如果没有提供则直接使用filter的name作为beanName,产生beanName后,由于我们在web.xml中的filter的name是springSecurityFilterChain。
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
FilterChainProxy
从Spring IOC容器中取出bean的代码是initDelegate方法。
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);if (isTargetFilterLifecycle()) {delegate.init(getFilterConfig());}return delegate;}在这个方法中,getTargetBeanName()返回的是Filter的name:springSecurityFilterChain
Filter delegate = wac.getBean(getTargetBeanName(),Filter.class)
这里根据springSecurityFilterChain的bean name直接获取FilterChainProxy的实例。可是springSecurityFilterChain这个bean在哪里定义的呢?此时似乎忽略了spring security的bean配置文件了。
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/ spring-security-3.0.xsd"> <http auto-config="true"> <intercept-url pattern="/*" access="ROLE_USER"/> </http> <authentication-manager alias="authenticationManager"> <authentication-provider> <user-service> <user authorities="ROLE_USER" name="guest" password="guest"/> </user-service> </authentication-provider> </authentication-manager> </beans:beans>
这是最简单的配置,同时也解开了springSecurityFilterChain这个bean没有定义的疑问。这里主要利用了spring的自定义标签。首先spring security的标签解析部分的源码包为:spring-security-config.jar中
spring security的标签解析由org.springframework.security.config.SecurityNamespaceHandler来处理。该类实现接口:NamespaceHandler,spring中自定义标签都要实现该接口,该接口有三个方法init、parse、decorate,其中init用于自定义标签的初始化,parse用于解析标签,decorate用于装饰。
SecurityNamespaceHandler类的init方法完成了标签解析类的注册工作
public void init() { loadParsers(); } @SuppressWarnings("deprecation") 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());//authentication-manager的标签解析类注册 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()); parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());//http的标签解析类注册 parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser()); parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser()); parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser()); parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser()); filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator(); } }
在SecurityNamespaceHandler类中定义了字段
private static final String FILTER_CHAIN_PROXY_CLASSNAME="org.springframework.security.web.FilterChainProxy";
HttpSecurityBeanDefinitionParser的parse方法源码为:
public BeanDefinition parse(Element element, ParserContext pc) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element)); pc.pushContainingComponent(compositeDef); final Object source = pc.extractSource(element); final String portMapperName = createPortMapper(element, pc); final UrlMatcher matcher = createUrlMatcher(element); HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, matcher, portMapperName); httpBldr.parseInterceptUrlsForEmptyFilterChains(); httpBldr.createSecurityContextPersistenceFilter(); httpBldr.createSessionManagementFilters(); ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>(); BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders, null); //过滤器是如何添加到链中的 是在这里进行设置的 httpBldr.createServletApiFilter(); httpBldr.createChannelProcessingFilter(); httpBldr.createFilterSecurityInterceptor(authenticationManager); AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc, httpBldr.isAllowSessionCreation(), portMapperName); authBldr.createAnonymousFilter(); authBldr.createRememberMeFilter(authenticationManager); authBldr.createRequestCache(); authBldr.createBasicFilter(authenticationManager); authBldr.createFormLoginFilter(httpBldr.getSessionStrategy(), authenticationManager); authBldr.createOpenIDLoginFilter(httpBldr.getSessionStrategy(), authenticationManager); authBldr.createX509Filter(authenticationManager); authBldr.createLogoutFilter(); authBldr.createLoginPageFilterIfNeeded(); authBldr.createUserServiceInjector(); authBldr.createExceptionTranslationFilter(); List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>(); //接下来完成Filter的排序、并添加到filterChainMap集合中 unorderedFilterChain.addAll(httpBldr.getFilters()); unorderedFilterChain.addAll(authBldr.getFilters()); authenticationProviders.addAll(authBldr.getProviders()); BeanDefinition requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class); requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", authBldr.getRequestCache()); unorderedFilterChain.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER)); unorderedFilterChain.addAll(buildCustomFilterList(element, pc)); Collections.sort(unorderedFilterChain, new OrderComparator()); checkFilterChainOrder(unorderedFilterChain, pc, source); List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>(); for (OrderDecorator od : unorderedFilterChain) { filterChain.add(od.bean); } ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap(); BeanDefinition universalMatch = new RootBeanDefinition(String.class); universalMatch.getConstructorArgumentValues().addGenericArgumentValue(matcher.getUniversalMatchPattern()); filterChainMap.put(universalMatch, filterChain); registerFilterChainProxy(pc, filterChainMap, matcher, source); // 此时已经为FilterChainProxy提供了必须的参数,接下来便是完成FilterChainProxy的bean定义过程了 pc.popAndRegisterContainingComponent(); return null; }
registerFilterChainProxy()方法的源码为:
private void registerFilterChainProxy(ParserContext pc, Map<BeanDefinition, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) { if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) { pc.getReaderContext().error("Duplicate <http> element detected", source); } //定义FilterChainProxy的BeanDefinition构造对象 BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class); fcpBldr.getRawBeanDefinition().setSource(source); fcpBldr.addPropertyValue("matcher", matcher); fcpBldr.addPropertyValue("stripQueryStringFromUrls", Boolean.valueOf(matcher instanceof AntUrlPathMatcher)); //注入过滤器链 fcpBldr.addPropertyValue("filterChainMap", filterChainMap); BeanDefinition fcpBean = fcpBldr.getBeanDefinition(); //注册bean pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY)); //注册bean的alias,其中别名为springSecurityFilterChain pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN); }
这里需要说明的是BeanDefinitionBuilder类,该类能够动态创建spring的bean,并通过ParserContext完成bean的注册,而不需要在xml中进行配置。
此时FilterChainProxy实例化过程已经完成。
下面再看一下DelegatingFilterProxy类的doFilter方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { // Lazily initialize the delegate if necessary. Filter delegateToUse = null; synchronized (this.delegateMonitor) { if (this.delegate == null) { WebApplicationContext wac = findWebApplicationContext(); if (wac == null) { throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?"); } this.delegate = initDelegate(wac); } delegateToUse = this.delegate; } // Let the delegate perform the actual doFilter operation. invokeDelegate(delegateToUse, request, response, filterChain); }真正要关注invokeDelegate(delegateToUse, request, response, filterChain);这句代码,在下面可以看出DelegatingFilterProxy类实际是用其delegate属性即org.springframework.security.FilterChainProxy实例的doFilter方法来响应请求。
protected void invokeDelegate( Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { delegate.doFilter(request, response, filterChain); }
以上就是DelegatingFilterProxy类的一些内部运行机制,其实主要作用就是一个代理模式的应用,可以把servlet 容器中的filter同spring容器中的bean关联起来。
- spring security之DelegatingFilterProxy和FilterChainProxy
- spring security:DelegatingFilterProxy和FilterChainProxy之间的关系
- Spring Web DelegatingFilterProxy和Spring Security Web Filter Chain
- Spring Security about DelegatingFilterProxy【转】
- spring之DelegatingFilterProxy
- Spring web过滤器-委派过滤器代理(DelegatingFilterProxy/FilterChainProxy)——Spring Security3源码分析
- spring security设置(springSecurityFilterChain与DelegatingFilterProxy)
- Spring之过滤器代理DelegatingFilterProxy
- spring-security中DelegatingFilterProxy的delegateMonitor的作用
- Spring DelegatingFilterProxy
- Spring-DelegatingFilterProxy
- Spring Security4.0.3源码分析之FilterChainProxy初始化
- Spring Security4.0.3源码分析之FilterChainProxy执行过程分析
- shiro与spring整合之DelegatingFilterProxy源码解析
- spring DelegatingFilterProxy管理过滤器
- spring security之ACL
- spring security之应用
- spring-security之ChannelProcessingFilter
- 求逆序数(光影切割问题)
- 一切成功源于积累——20141121 因为有钱,因为任性
- 采用CSS3设计的登陆界面
- Floating Point IEEE745
- 一步一步学zedboard之十一可用bootloader的生成
- spring security之DelegatingFilterProxy和FilterChainProxy
- 入门createjs———easelJS教程(1)绘制一个圆形
- [HTML5&CSS3]应用程序缓存
- sql server2008远程连接不上?
- 脚本之查询库缓存上的PIN命中率
- 问题解决——ShowWindow不显示窗口
- C++编程学习50个经典网站
- OpenCv cv::Mat类用法1
- Android 在WebView中显示页面而不是默认浏览器中