2015-05-12 3 views
1

Мы используем функцию Spring, которая инициализируется с использованием AbstractSecurityWebApplicationInitializer. У нас также есть отдельный инициатор веб-приложений, который простирается от AbstractAnnotationConfigDispatcherServletInitializer. Я сделал последнее как @Order(Ordered.HIGHEST_PRECEDENCE), как указано в Javadoc первого. Все идет нормально.Как использовать Spring DelegatingFilterProxy с несколькими фильтрами и Spring Security?

Теперь я хочу представить дополнительные фильтры сервлета, которые не имеют отношения к безопасности Spring и поэтому должны быть настроены отдельно. Я знаю, что я могу использовать DelegatingFilterProxy для делегирования запросов на фильтр. Но DelegatingFilterProxy не может принимать несколько фильтров. Одним из вариантов является определение пользовательского FilterChain, как это сделано в Spring Security FilterChainProxy. Это все еще создает 2 DelegatingFilterProxy, и я понимаю, что в приложении должно быть только одно DelegatingFilterProxy.

Любые идеи?

ответ

0

Отвечая на мой собственный вопрос, это то, как я это сделал:

Я подклассы AbstractAnnotationConfigDispatcherServletInitializer и в нем:

/** 
    * {@inheritDoc} 
    */ 
    @Override 
    protected Filter[] getServletFilters() { 
     return new Filter[] { requestContextFilter(), teFilterChain() }; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    protected FilterRegistration.Dynamic registerServletFilter(
      ServletContext servletContext, Filter filter) { 
     String filterName = Conventions.getVariableName(filter); 
     Dynamic registration = servletContext.addFilter(filterName, filter); 
     if (registration == null) { 
      int counter = -1; 
      while (counter == -1 || registration == null) { 
       counter++; 
       registration = servletContext 
         .addFilter(filterName + "#" + counter, filter); 
       Assert.isTrue(counter < 100, "Failed to register filter '" 
         + filter + "'." 
         + "Could the same Filter instance have been registered already?"); 
      } 
     } 
     registration.setAsyncSupported(isAsyncSupported()); 

     registration.addMappingForServletNames(getDispatcherTypes(), false, 
       getServletName()); 
     return registration; 
    } 

    /** 
    * Spring, by default, registers filters for 'FORWARD' dispatcher type as 
    * well which causes TE filter chain to run again after Spring security 
    * successfully authenticates and forwards the incoming request. We thus 
    * exclude 'FORWARD' dispatcher type. 
    */ 
    private EnumSet<DispatcherType> getDispatcherTypes() { 
     return (isAsyncSupported() 
       ? EnumSet.of(DispatcherType.REQUEST, DispatcherType.INCLUDE, 
         DispatcherType.ASYNC) 
       : EnumSet.of(DispatcherType.REQUEST, DispatcherType.INCLUDE)); 
    } 

    private Filter requestContextFilter() { 
     return new DelegatingFilterProxy(TE_REQ_CTX_FILTER); 
    } 

    private Filter teFilterChain() { 
     return new DelegatingFilterProxy(TE_FILTER_CHAIN); 
    } 

    @Override 
    protected void registerDispatcherServlet(ServletContext ctx) { 
     super.registerDispatcherServlet(ctx); 

     registerSpringSecurityFilter(ctx); 
     registerCorsFilter(ctx); 
    } 

    @Override 
    protected DispatcherServlet createDispatcherServlet(
      WebApplicationContext servletAppContext) { 
     DispatcherServlet servlet = new DispatcherServlet(servletAppContext); 
     servlet.setThreadContextInheritable(true); 
     servlet.setThrowExceptionIfNoHandlerFound(true); 

     return servlet; 
    } 

    private Dynamic registerCorsFilter(ServletContext ctx) { 
     Dynamic registration = ctx.addFilter("CorsFilter", CorsFilter.class); 

     registration.setInitParameter(CorsFilter.PARAM_CORS_ALLOWED_ORIGINS, 
       CORS_ALLOWED_ORIGINS); 
     registration.setInitParameter(CorsFilter.PARAM_CORS_ALLOWED_METHODS, 
       CORS_ALLOWED_METHODS); 
     registration.setInitParameter(CorsFilter.PARAM_CORS_ALLOWED_HEADERS, 
       CORS_ALLOWED_HEADERS); 

     registration.addMappingForUrlPatterns(getDispatcherTypes(), false, 
       "/*"); 

     return registration; 
    } 

    @Override 
    protected boolean isAsyncSupported() { 
     return true; 
    } 

    private final FilterRegistration.Dynamic registerSpringSecurityFilter(
      ServletContext servletContext) { 
     FilterRegistration.Dynamic registration = servletContext.addFilter(
       SPRING_SECURITY_FILTER_CHAIN, springSecurityFilterChain()); 

     if (registration == null) { 
      throw new IllegalStateException("Duplicate Filter registration for " 
        + SPRING_SECURITY_FILTER_CHAIN 
        + "'. Check to ensure the Filter is only configured once."); 
     } 

     registration.setAsyncSupported(isAsyncSupported()); 
     EnumSet<DispatcherType> dispatcherTypes = getSecurityDispatcherTypes(); 
     /* 
     * Don't use URL mapping for registering Spring security because then 
     * the chain will kick in before DispatcherServlet. 
     */ 
     registration.addMappingForServletNames(dispatcherTypes, true, 
       getServletName()); 

     return registration; 
    } 

    private Filter springSecurityFilterChain() { 
     return new DelegatingFilterProxy(SPRING_SECURITY_FILTER_CHAIN); 
    } 

    protected EnumSet<DispatcherType> getSecurityDispatcherTypes() { 
     return EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR, 
       DispatcherType.ASYNC); 
    }