CharacterEncodingFilter 不能与 Spring Security 3.2.0 一起使用
Posted
技术标签:
【中文标题】CharacterEncodingFilter 不能与 Spring Security 3.2.0 一起使用【英文标题】:CharacterEncodingFilter don't work together with Spring Security 3.2.0 【发布时间】:2014-01-18 18:03:22 【问题描述】:我是 Spring MVC 框架的新手,我遇到了一个我自己无法解决的问题。当我将 spring security 与我的应用程序集成时,一切都开始了,之后 html 表单中的所有 unicode 值都没有被编码(spring security 工作正常)。我得出的结论是,这可能是因为我的DelegatingFilterProxy
被称为链中的第一个过滤器。
这是我认为可行的配置,但它不起作用:
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
【问题讨论】:
做一个优秀的 SO 公民并标记正确的答案。 你说你在重新安装 Tomcat 后让它工作了?还有更多细节吗? 【参考方案1】:我不知道 什么 到底是什么问题,但我永远不会在 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
的过滤器映射之前)。
【讨论】:
您的回答是 100% 有效,因为我尝试了这个解决方案并解决了我的问题,但是对于这个项目,我想完全避免使用 web.xml(我应该在问题中提到这一点 - 抱歉没有指定这个) 在委派过滤器代理之前配置编码过滤器很重要。它解决了我持续数月的问题。现在该应用程序使用 unicode 可以正常工作。【参考方案2】:有同样的问题。我的解决方案是使用原始 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 上。
【讨论】:
我会将此答案标记为正确,因为它显示了解决 web.xml 之外的字符编码问题的替代解决方案。我还想提一下,重写 AbstractAnnotationConfigDispatcherServletInitializer 类的 getServletMappings() 方法将使其正常工作。正如您将看到的那样,我使用了这种方法,但是在重新安装 tomcat 后它开始起作用了。 我遇到了同样的问题,但上述方法均无效。相反,我删除了 SecurityWebApplicationInitializer 类,只是在 getServletFilters 方法中添加了 spring 安全过滤器。 这几乎对我有用。在我确定 CharacterEncodingFilter 是 filterChain 中第一个处理请求之前,它没有任何效果。要确保 characterEncodingFilter 位于链中的第一位,您需要将 addMappingForUrlPatterns 中的中间参数更改为 false。值 false 确保 CharacterEncodingFilter 是链中的第一个过滤器,值 true 将过滤器添加到 filterChain 的末尾。 wildfly 8 也会发生【参考方案3】:我们需要在第一次读取请求属性的过滤器之前添加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
【讨论】:
没错,尝试了所有其他解决方案,这个对我有用。 这是唯一对我有用的东西。我本来希望 Christian Nilsson 的解决方案能够工作,但在 Spring Security 的上下文中,它没有 很遗憾,但建议的解决方案对我不起作用。我已经尝试了在 Internet 上找到的所有组合,但仍在寻找解决方案。 带有原生 Spring Security 的 Grails 4.0.10 有同样的错误:UTF8 输入的表单数据将以 iso-8859-1 呈现。上述解决方案就像一个魅力。非常感谢。【参考方案4】:我最近遇到了同样的问题,您的第一次尝试实际上与我最终使用的解决方案非常接近(这是您的代码,已修复):
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)。
【讨论】:
这是最好的非web.xml解决方案。【参考方案5】:我不喜欢到目前为止发布的答案,因为要么使用晦涩的 Spring 类,要么依赖于实现细节。
在我看来,事情应该通过简单地定义一个标准@Bean
和高@Order
来工作,所以这是Boot 的错 - 但幸运的是,如果我们使用FilterRegistrationBean
而不是普通的@,一切都会按预期工作(?) 987654324@(我使用的是 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;
【讨论】:
【参考方案6】:我用过
@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
【讨论】:
以上是关于CharacterEncodingFilter 不能与 Spring Security 3.2.0 一起使用的主要内容,如果未能解决你的问题,请参考以下文章
CharacterEncodingFilter-Spring字符编码过滤器
Servlet 中 CharacterEncodingFilter 失效?
CharacterEncodingFilter 不能与 Spring Security 3.2.0 一起使用
CharacterEncodingFilter详解及源码解析
org.springframework.web.filter.CharacterEncodingFilter 不能转换为 javax.servlet.Filter