web-dev-qa-db-fra.com

CharacterEncodingFilter ne fonctionne pas avec Spring Security 3.2.0

Je suis nouveau dans le framework Spring MVC et j'ai un problème que je ne peux pas résoudre moi-même. Tout a commencé lorsque j'ai intégré la sécurité Spring à mon application, après quoi toutes les valeurs Unicode du formulaire HTML n'étaient pas codées (la sécurité Spring fonctionne correctement). J'en suis venu à la conclusion que cela se produit probablement parce que mon DelegatingFilterProxy est appelé comme le premier filtre de la chaîne.

Voici ma configuration que je pensais fonctionner, mais elle ne fonctionne pas:

1) J'étends AbstractSecurityWebApplicationInitializer - à partir de javadoc:

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

De cette classe, je remplace également la méthode beforeSpringSecurityFilterChain qui, en ce qui concerne javadoc:

Invoked before the springSecurityFilterChain is added.

J'ai donc pensé que ce serait le meilleur endroit pour enregistrer 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, "/*");
    }
}

Mais cela ne fonctionne pas.

Une autre option que je fatiguais était d'enregistrer le filtre via la classe AbstractAnnotationConfigDispatcherServletInitializer en remplaçant la méthode 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};
    }
}

Mais cela ne fonctionne pas non plus. Quelqu'un rencontre-t-il le même problème ou a-t-il des idées pour résoudre ce problème?

Voici ma configuration complète pour la première option où j'enregistre le filtre de codage via 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);
    }
}

Dépendances:

spring-mvc 3.2.5.RELEASE

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

J'y travaille sous le lien suivant: https://github.com/ajurasz/Manager

33
ajurasz

J'ai le même problème. Ma solution a été d'utiliser un filtre de servlet brut:

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, "/*");
}

Notez que ce problème se produit uniquement avec Tomcat mais pas avec Jetty.

11
Christian Nilsson

Nous devons ajouter CharacterEncodingFilter avant les filtres qui lisent les propriétés de la demande pour la première fois. Il y a securityFilterChain (se place en deuxième position après le filtre métrique) et nous pouvons y ajouter notre filtre. Le premier filtre (à l'intérieur de la chaîne de sécurité) qui lit les propriétés est CsrfFilter, nous plaçons donc CharacterEncodingFilter avant lui.

La solution courte est:

@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
}
59
Alexandr Latushkin

J'ai rencontré le même problème récemment et votre premier essai est en fait très proche de la solution que j'ai fini par utiliser (voici votre code, corrigé):

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 seule différence est le deuxième argument lors de l'ajout d'un mappage de filtre pour les modèles d'URL. Javadoc pour ce paramètre indique:

isMatchAfter - true si le mappage de filtre donné doit être mis en correspondance après tout mappage de filtre déclaré, et false s'il est censé être mis en correspondance avant tout mappage de filtre déclaré du ServletContext à partir duquel ce FilterRegistration a été obtenu

Donc, le définir sur false devrait résoudre proprement votre problème (sans aucun XML impliqué).

17
m4rtin

Je ne sais pas quoi exactement le problème est mais je n'aurais jamais configuré un filtre aussi simple à l'intérieur de Spring. Faites-le bien dans web.xml - plus facile à développer, à comprendre et à déboguer.

  <!-- 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>

Important: configurez le mappage de ce filtre avant la chaîne de filtres Spring Security (c'est-à-dire avant le mappage de filtre pour DelegatingFilterProxy).

14
Marcel Stör

J'ai utilisé

@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
}
3
manh

Je n'aime pas les réponses publiées jusqu'à présent car soit utilisez des classes Spring obscures, soit utilisez des détails d'implémentation.

À mon avis, les choses devraient fonctionner en définissant simplement une norme @Bean avec haut @Order, c'est donc la faute de Boot - mais heureusement tout fonctionne comme prévu (?) si nous utilisons un FilterRegistrationBean au lieu d'un simple Filter (j'utilise 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;
}
2
Raffaele