【问题标题】:How to use Spring DelegatingFilterProxy with multiple filters and Spring Security?如何使用带有多个过滤器和 Spring Security 的 Spring DelegatingFilterProxy?
【发布时间】:2015-07-23 21:58:17
【问题描述】:

我们使用的是使用 AbstractSecurityWebApplicationInitializer 初始化的 Spring 安全性。我们还有一个从 AbstractAnnotationConfigDispatcherServletInitializer 扩展的单独的 Web 应用初始化程序。按照前者的 Javadoc 中的建议,我将后者设置为 @Order(Ordered.HIGHEST_PRECEDENCE)。到目前为止一切顺利。

现在我想介绍额外的 Servlet 过滤器,这些过滤器与 Spring 安全性无关,因此应该单独配置。我知道我可以使用DelegatingFilterProxy 将请求委托给过滤器。但是DelegatingFilterProxy 没有接受多个过滤器的能力。 一种选择是定义一个自定义的FilterChain,就像在 Spring Security FilterChainProxy 中所做的那样。这仍然会创建 2 个DelegatingFilterProxy,我知道应用程序中应该只有一个DelegatingFilterProxy

有什么想法吗?

【问题讨论】:

    标签: spring-mvc filter spring-security


    【解决方案1】:

    回答我自己的问题,我就是这样做的:

    我继承了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);
        }
    

    【讨论】:

    • 你不能使用FilterChainProxy吗?
    • @lqbweb 3.5 年后,我不记得了。
    猜你喜欢
    • 2012-06-23
    • 2019-04-13
    • 2015-12-04
    • 2018-05-25
    • 2020-09-21
    • 2018-02-14
    • 2012-09-28
    • 2018-01-15
    • 2015-10-13
    相关资源
    最近更新 更多