如何将Spring DelegatingFilterProxy与多个过滤器和Spring Security一起使用?

时间:2015-05-12 20:30:38

标签: spring-mvc filter spring-security

我们使用的是使用AbstractSecurityWebApplicationInitializer初始化的Spring安全性。我们还有一个单独的网络应用初始值设定项,从AbstractAnnotationConfigDispatcherServletInitializer扩展而来。我按照前者Javadoc的建议将@Order(Ordered.HIGHEST_PRECEDENCE)作为后者。到目前为止一切都很好。

现在我想介绍一些与Spring安全无关的其他Servlet过滤器,因此应该单独配置。我知道我可以使用DelegatingFilterProxy将请求委托给过滤器。但DelegatingFilterProxy无法接受多个过滤器。 一种选择是在Spring Security FilterChain中定义自定义FilterChainProxy。这仍然会创建2个DelegatingFilterProxy,我知道应用中应该只有一个DelegatingFilterProxy

有什么想法吗?

1 个答案:

答案 0 :(得分: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);
    }