34

我是 Spring MVC 框架的新手,我遇到了一个我自己无法解决的问题。当我将 spring security 与我的应用程序集成时,一切都开始了,之后 HTML 表单中的所有 unicode 值都没有被编码(spring security 工作正常)。我得出的结论是,这可能是因为 myDelegatingFilterProxy被称为链中的第一个过滤器。

这是我认为可行的配置,但它没有:

1)我正在扩展 AbstractSecurityWebApplicationInitializer - 从 javadoc:

Registers the DelegatingFilterProxy to use the springSecurityFilterChain() before any
other registered Filter.

从该类中,我还覆盖了关于 javadoc 的 beforeSpringSecurityFilterChain 方法:

Invoked before the springSecurityFilterChain is added.

所以我认为这将是注册 CharacterEncodingFilter 的最佳位置:

public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
        characterEncodingFilter.setInitParameter("encoding", "UTF-8");
        characterEncodingFilter.setInitParameter("forceEncoding", "true");
        characterEncodingFilter.addMappingForUrlPatterns(null, true, "/*");
    }
}

但这不起作用。

我厌倦的另一个选择是通过覆盖 getServletFilters() 方法通过 AbstractAnnotationConfigDispatcherServletInitializer 类注册过滤器:

public class WebAppInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    //{!begin addToRootContext}
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { SecurityConfig.class, DatabaseConfig.class, InternationalizationConfig.class };
    }
    //{!end addToRootContext}

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebAppConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected Filter[] getServletFilters() {

        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceEncoding(true);
        return new Filter[] { characterEncodingFilter};
    }
}

但这也不起作用。有没有人遇到同样的问题或有一些想法如何解决这个问题?

这是我通过 AbstractSecurityWebApplicationInitializer 注册编码过滤器的第一个选项的完整配置:

@Order(1)
public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
        characterEncodingFilter.setInitParameter("encoding", "UTF-8");
        characterEncodingFilter.setInitParameter("forceEncoding", "true");
        characterEncodingFilter.addMappingForUrlPatterns(null, true, "/*");
    }
}

@Order(2)
public class WebAppInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    //{!begin addToRootContext}
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { SecurityConfig.class, DatabaseConfig.class, InternationalizationConfig.class };
    }
    //{!end addToRootContext}

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebAppConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

@EnableWebMvc
//@Import(value = {DatabaseConfig.class, InternationalizationConfig.class, SecurityConfig.class})
@ComponentScan(basePackages = {"com.ajurasz.controller", "com.ajurasz.service", "com.ajurasz.model"})
@Configuration
public class WebAppConfig extends WebMvcConfigurerAdapter {

    @Bean
    public UrlBasedViewResolver viewResolver() {
        UrlBasedViewResolver urlBasedViewResolver = new UrlBasedViewResolver();
        urlBasedViewResolver.setViewClass(TilesView.class);
        urlBasedViewResolver.setContentType("text/html;charset=UTF-8");
        return urlBasedViewResolver;
    }

    @Bean
    public TilesConfigurer tilesConfigurer() {
        TilesConfigurer tilesConfigurer = new TilesConfigurer();
        tilesConfigurer.setDefinitions(new String[] {"/WEB-INF/tiles.xml"});
        return tilesConfigurer;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/**");
        registry.addResourceHandler("/documents/**").addResourceLocations("/WEB-INF/pdfs/documents/**");
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        PageableHandlerMethodArgumentResolver pageableHandlerMethodArgumentResolver =
                new PageableHandlerMethodArgumentResolver();
        pageableHandlerMethodArgumentResolver.setFallbackPageable(new PageRequest(0, 4, new Sort(Sort.Direction.DESC, "id")));

        argumentResolvers.add(pageableHandlerMethodArgumentResolver);
    }
}

依赖项:

spring-mvc 3.2.5.RELEASE

spring-security-config,spring-security-web,spring-security-core 3.2.0.RELEASE

我正在通过以下链接处理此问题: https ://github.com/ajurasz/Manager

4

6 回答 6

65

我们需要在第一次读取请求属性的过滤器之前添加 CharacterEncodingFilter。有 securityFilterChain(排在第二位。在 metrica 过滤器之后),我们可以在其中添加我们的过滤器。读取属性的第一个过滤器(在安全链内)是 CsrfFilter,因此我们将 CharacterEncodingFilter 放在它之前。

简短的解决方案是:

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceEncoding(true);
        http.addFilterBefore(filter,CsrfFilter.class);
        //rest of your code   
    }
//rest of your code
}
于 2014-04-14T02:57:29.637 回答
20

我最近遇到了同样的问题,您的第一次尝试实际上与我最终使用的解决方案非常接近(这是您的代码,已修复):

public class MessageSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
@Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
    FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("encodingFilter", new CharacterEncodingFilter());
    characterEncodingFilter.setInitParameter("encoding", "UTF-8");
    characterEncodingFilter.setInitParameter("forceEncoding", "true");
    characterEncodingFilter.addMappingForUrlPatterns(null, false, "/*");
    }
}

唯一的区别是为 url 模式添加过滤器映射时的第二个参数。此参数的Javadoc指出:

isMatchAfter - 如果给定的过滤器映射应该在任何声明的过滤器映射之后匹配,则为 true;如果它应该在获得此 FilterRegistration 的 ServletContext 的任何声明的过滤器映射之前匹配,则为 false

因此,将其设置为 false 应该可以彻底解决您的问题(不涉及任何 XML)。

于 2014-04-30T21:08:06.750 回答
15

我不知道究竟是什么问题,但我永远不会在 Spring 中配置如此简单的过滤器。而是正确地做web.xml——更容易开发、理解和调试。

  <!-- Hint: http://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q8 -->
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

重要:在 Spring Security 过滤器链之前配置此过滤器的映射(即在过滤器映射之前DelegatingFilterProxy)。

于 2013-12-31T23:12:52.840 回答
10

有同样的问题。我的解决方案是使用原始 servlet 过滤器:

public void onStartup(ServletContext servletContext) throws ServletException {
      FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encoding-filter", new CharacterEncodingFilter());
      encodingFilter.setInitParameter("encoding", "UTF-8");
      encodingFilter.setInitParameter("forceEncoding", "true");
      encodingFilter.addMappingForUrlPatterns(null, true, "/*");
}

请注意,此问题仅发生在 Tomcat 上,但不发生在 Jetty 上。

于 2014-01-20T09:01:25.923 回答
2

我用过

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceEncoding(true);
        http.addFilterBefore(filter,CsrfFilter.class);
        //rest of your code   
    }
//rest of your code
}
于 2015-12-12T03:45:24.290 回答
1

我不喜欢到目前为止发布的答案,因为要么使用晦涩的 Spring 类,要么依赖于实现细节。

在我看来,事情应该通过简单地定义一个标准@Bean来工作 high @Order,所以这是 Boot 的错 - 但幸运的是,如果我们使用 aFilterRegistrationBean而不是普通的Filter(我使用的是 Boot 1.1.5),一切都会按预期工作(?):

@Bean
public FilterRegistrationBean filterRegistrationBean() {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
    registrationBean.setFilter(characterEncodingFilter);
    characterEncodingFilter.setEncoding("UTF-8");
    characterEncodingFilter.setForceEncoding(true);
    registrationBean.setOrder(Integer.MIN_VALUE);
    registrationBean.addUrlPatterns("/*");
    return registrationBean;
}
于 2014-09-11T19:10:58.423 回答