spring mvc - ejemplo - CharacterEncodingFilter no funciona junto con Spring Security 3.2.0
spring security tutorial (6)
Soy nuevo en el framework Spring MVC y tengo un problema que no puedo resolver solo. Todo comenzó cuando integé la seguridad de primavera con mi aplicación, después de eso todos los valores Unicode del formato HTML no estaban codificados (la seguridad de primavera funciona correctamente). Llegué a la conclusión de que esto está sucediendo, probablemente porque mi DelegatingFilterProxy
se llama como el primer filtro de la cadena.
Aquí está mi configuración que pensé que funcionaría, pero no es así:
1) Extiendo AbstractSecurityWebApplicationInitializer - de javadoc:
Registers the DelegatingFilterProxy to use the springSecurityFilterChain() before any
other registered Filter.
De esa clase también anulo beforeSpringSecurityFilterChain método que con respecto a javadoc:
Invoked before the springSecurityFilterChain is added.
Así que pensé que este sería el mejor lugar para registrar 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, "/*");
}
}
Pero esto no funciona.
Otra opción que me cansé fue registrar el filtro a través de la clase AbstractAnnotationConfigDispatcherServletInitializer anulando el método getServletFilters ():
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};
}
}
Pero esto tampoco funciona. ¿Alguien se encuentra con el mismo problema o tiene algunas ideas de cómo resolver esto?
Aquí está mi configuración completa para la primera opción donde estoy registrando el filtro de codificación a través de 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);
}
}
Dependencias:
spring- mvc 3.2.5.RELEASE
spring-security-config, spring-security-web, spring-security-core 3.2.0.RELEASE
Estoy trabajando en esto en el siguiente enlace: https://github.com/ajurasz/Manager
He usado
@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
}
Me encontré con el mismo problema recientemente y su primer intento es en realidad muy cercano a la solución que terminé usando (aquí está su código, corregido):
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, "/*");
}
}
La única diferencia es el segundo argumento al agregar mapeo de filtro para patrones de url. El Javadoc para este parámetro dice:
isMatchAfter - verdadero si el mapeo de filtro dado debe coincidir después de cualquier mapeo de filtro declarado, y falso si se supone que debe coincidir antes de cualquier mapeo de filtro declarado del ServletContext del que se obtuvo este FilterRegistration
Por lo tanto, configurarlo en falso debería resolver su problema limpiamente (sin ningún XML involucrado).
Necesitamos agregar CharacterEncodingFilter antes de los filtros que leen las propiedades de las solicitudes por primera vez. Hay securityFilterChain (está en segundo lugar después del filtro metrica) y podemos agregar nuestro filtro dentro de él. El primer filtro (dentro de la cadena de seguridad) que lee propiedades es CsrfFilter, por lo que colocamos CharacterEncodingFilter antes.
La solución corta es:
@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
}
No me gustan las respuestas publicadas hasta ahora, ya sea porque utilizo las clases oscuras de Spring o porque confío en los detalles de implementación.
En mi opinión, las cosas deberían funcionar simplemente definiendo un @Bean
estándar con alta @Order
, así que esto es culpa de Boot, pero afortunadamente todo funciona como se espera (?) Si utilizamos FilterRegistrationBean
lugar de un Filter
simple (estoy usando 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;
}
No sé exactamente cuál es el problema, pero nunca configuré un filtro tan simple dentro de Spring. Más bien hazlo bien en web.xml
: más fácil de desarrollar, comprender y depurar.
<!-- 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>
Importante: configure la asignación de este filtro antes de la cadena de filtro Spring Security (es decir, antes de la asignación de filtro para DelegatingFilterProxy
).
Tiene el mismo problema Mi solución fue usar un filtro de servlet sin procesar:
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, "/*");
}
Tenga en cuenta que este problema solo se produce con Tomcat, pero no con Jetty.