springsecurity之springSecurityFilterChain

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hepei120/article/details/80561556

如果在web项目中增加springsecurity作为你的登录认证授权框架,那么第一步就需要在web.xml 增加如下配置

 <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>


而DelegatingFilterProxy并不是真正工作的Filter。先看一下org.springframework.web.filter.DelegatingFilterProxy.java的源码

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

@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) {
         if (this.delegate == null) {
            WebApplicationContext wac = findWebApplicationContext();
            if (wac == null) {
               throw new IllegalStateException("No WebApplicationContext found: " +
                     "no ContextLoaderListener or DispatcherServlet registered?");
            }
            this.delegate = initDelegate(wac);
         }
         delegateToUse = this.delegate;
      }
   }

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

将filtername('springSecurityFilterChain')作为targetBeanName,从WebApplicationContext通过getBean()获取FilterChainProxy的实例。

最终FilterChainProxy还是把工作交给了FilterList来处理,其中保存的就是Security系统中的一系列Filter。那么这些Filter也是在解析配置文件的时候注册到上下文中的。下面具体看下Security配置文件的解析,主要是<http>标签。


二、这是一段springsecurity的xml配置文件的一段内容

 <http pattern="/static/**" security="none" /> 
   <http pattern="/WEB-INF/views/jsp/common/403.jsp" security="none" /> 
   <http pattern="/WEB-INF/views/jsp/common/login.jsp" security="none" /> 
   <http pattern="/403" security="none" /> 
   <http pattern="/login" security="none" />
<http  use-expressions="true" >
    <intercept-url pattern="/login"    access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/**" access="isAuthenticated()"/>
    <access-denied-handler ref="accessDeniedHandler"/>
    <form-login login-page="/login" default-target-url="/login"
                   authentication-failure-url="/login"
                   always-use-default-target="true"
                   username-parameter="userName"
                   password-parameter="password"
                   login-processing-url="/userLogin"
                   authentication-success-handler-ref="authenticationDispatcher"
                   authentication-failure-handler-ref="ylpaAuthenticationFailureHandler" /> 
       <custom-filter ref="customFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
       <custom-filter ref="customLogout" position="LOGOUT_FILTER" />
       
   <session-management invalid-session-url="/login">
      <concurrency-control max-sessions="1"
         expired-url="/login" />
   </session-management>
   <csrf disabled="true" />
</http> 

先找到是哪一个自定义的NamespaceHandler来解析该内容。


SecurityNamespaceHandler.java对各个标签使用的解析标签类

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

HTTP 标签使用的是

HttpSecurityBeanDefinitionParser
@SuppressWarnings({ "unchecked" })
@Override
public BeanDefinition parse(Element element, ParserContext pc) {
   CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(
         element.getTagName(), pc.extractSource(element));
   pc.pushContainingComponent(compositeDef);

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

   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));
   //将FilterChainProxy实例别名注册为springSecurityFilterChain
   pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY,
         BeanIds.SPRING_SECURITY_FILTER_CHAIN);
}
//一系列的filter 注册。还有下一节要讲的ProviderManager的创建就是从这个方法createAuthenticationManager 
private BeanReference createFilterChain(Element element, ParserContext pc) {
   ////判断http节点的security属性是否为none值,如果是,则返回一个空的过滤器链,表示这个url不经过springsecurity的拦截
   boolean secured = !OPT_SECURITY_NONE.equals(element.getAttribute(ATT_SECURED));

   if (!secured) {
      if (!StringUtils.hasText(element.getAttribute(ATT_PATH_PATTERN))
            && !StringUtils.hasText(ATT_REQUEST_MATCHER_REF)) {
         pc.getReaderContext().error(
               "The '" + ATT_SECURED
                     + "' attribute must be used in combination with"
                     + " the '" + ATT_PATH_PATTERN + "' or '"
                     + ATT_REQUEST_MATCHER_REF + "' attributes.",
               pc.extractSource(element));
      }

      for (int n = 0; n < element.getChildNodes().getLength(); n++) {
         if (element.getChildNodes().item(n) instanceof Element) {
            pc.getReaderContext().error(
                  "If you are using <http> to define an unsecured pattern, "
                        + "it cannot contain child elements.",
                  pc.extractSource(element));
         }
      }

      return createSecurityFilterChainBean(element, pc, Collections.emptyList());
   }

   final BeanReference portMapper = createPortMapper(element, pc);
   final BeanReference portResolver = createPortResolver(portMapper, pc);

   ManagedList<BeanReference> authenticationProviders = new ManagedList<>();
   BeanReference authenticationManager = createAuthenticationManager(element, pc,
         authenticationProviders);

   boolean forceAutoConfig = isDefaultHttpConfig(element);
   //对有关于http请求的节点属性进行解析
   HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element,
         forceAutoConfig, pc, portMapper, portResolver, authenticationManager);
   //对授权认证方面节点属性进行解析
   AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element,
         forceAutoConfig, pc, httpBldr.getSessionCreationPolicy(),
         httpBldr.getRequestCache(), authenticationManager,
         httpBldr.getSessionStrategy(), portMapper, portResolver,
         httpBldr.getCsrfLogoutHandler());
   //设置登出成功的处理器
   httpBldr.setLogoutHandlers(authBldr.getLogoutHandlers());
   httpBldr.setEntryPoint(authBldr.getEntryPointBean());
   httpBldr.setAccessDeniedHandler(authBldr.getAccessDeniedHandlerBean());

   authenticationProviders.addAll(authBldr.getProviders());

   List<OrderDecorator> unorderedFilterChain = new ArrayList<>();
   //添加关于http的一些拦截器
   unorderedFilterChain.addAll(httpBldr.getFilters());
   //添加授权认证的一些拦截器
   unorderedFilterChain.addAll(authBldr.getFilters());
   //添加自定义拦截器
   unorderedFilterChain.addAll(buildCustomFilterList(element, pc));

   Collections.sort(unorderedFilterChain, new OrderComparator());
   checkFilterChainOrder(unorderedFilterChain, pc, pc.extractSource(element));

   // The list of filter beans
   List<BeanMetadataElement> filterChain = new ManagedList<>();

   for (OrderDecorator od : unorderedFilterChain) {
      filterChain.add(od.bean);
   }
   //返回封装后的过滤器链
   return createSecurityFilterChainBean(element, pc, filterChain);
}

public abstract class BeanIds {
   private static final String PREFIX = "org.springframework.security.";

   /**
    * The "global" AuthenticationManager instance, registered by the
    * &lt;authentication-manager&gt; element
    */
   public static final String AUTHENTICATION_MANAGER = PREFIX + "authenticationManager";

   /** External alias for FilterChainProxy bean, for use in web.xml files */
   public static final String SPRING_SECURITY_FILTER_CHAIN = "springSecurityFilterChain";

   public static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = PREFIX
         + "contextSettingPostProcessor";

   public static final String USER_DETAILS_SERVICE = PREFIX + "userDetailsService";
   public static final String USER_DETAILS_SERVICE_FACTORY = PREFIX
         + "userDetailsServiceFactory";

   public static final String METHOD_ACCESS_MANAGER = PREFIX
         + "defaultMethodAccessManager";

   public static final String FILTER_CHAIN_PROXY = PREFIX + "filterChainProxy";
   public static final String FILTER_CHAINS = PREFIX + "filterChains";

   public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX
         + "methodSecurityMetadataSourceAdvisor";
   public static final String EMBEDDED_APACHE_DS = PREFIX
         + "apacheDirectoryServerContainer";
   public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource";

   public static final String DEBUG_FILTER = PREFIX + "debugFilter";
}
}
展开阅读全文

没有更多推荐了,返回首页